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.
5 *
6 * Author: Adam Jackson <[email protected]>
7 * Maintainer: Hans Verkuil <[email protected]>
8 */
9
10 #include <math.h>
11
12 #include "edid-decode.h"
13
14 static const char *bpc444[] = {"6", "8", "10", "12", "14", "16", NULL, NULL};
15 static const char *bpc4xx[] = {"8", "10", "12", "14", "16", NULL, NULL, NULL};
16 static const char *audiorates[] = {"32", "44.1", "48", NULL, NULL, NULL, NULL, NULL};
17
18 // misc functions
19
print_flags(const char * label,unsigned char flag_byte,const char ** flags,bool reverse=false)20 static void print_flags(const char *label, unsigned char flag_byte,
21 const char **flags, bool reverse = false)
22 {
23 if (!flag_byte)
24 return;
25
26 unsigned countflags = 0;
27
28 printf("%s: ", label);
29 for (unsigned i = 0; i < 8; i++) {
30 if (flag_byte & (1 << (reverse ? 7 - i : i))) {
31 if (countflags)
32 printf(", ");
33 if (flags[i])
34 printf("%s", flags[i]);
35 else
36 printf("Undefined (%u)", i);
37 countflags++;
38 }
39 }
40 printf("\n");
41 }
42
check_displayid_datablock_revision(unsigned char hdr,unsigned char valid_flags,unsigned char rev)43 void edid_state::check_displayid_datablock_revision(unsigned char hdr,
44 unsigned char valid_flags,
45 unsigned char rev)
46 {
47 unsigned char revision = hdr & 7;
48 unsigned char flags = hdr & ~7 & ~valid_flags;
49
50 if (revision != rev)
51 warn("Unexpected revision (%u != %u).\n", revision, rev);
52 if (flags)
53 warn("Unexpected flags (0x%02x).\n", flags);
54 }
55
check_displayid_datablock_length(const unsigned char * x,unsigned expectedlenmin=0,unsigned expectedlenmax=128-2-5-3,unsigned payloaddumpstart=0)56 static bool check_displayid_datablock_length(const unsigned char *x,
57 unsigned expectedlenmin = 0,
58 unsigned expectedlenmax = 128 - 2 - 5 - 3,
59 unsigned payloaddumpstart = 0)
60 {
61 unsigned char len = x[2];
62
63 if (expectedlenmin == expectedlenmax && len != expectedlenmax)
64 fail("DisplayID payload length is different than expected (%d != %d).\n", len, expectedlenmax);
65 else if (len > expectedlenmax)
66 fail("DisplayID payload length is greater than expected (%d > %d).\n", len, expectedlenmax);
67 else if (len < expectedlenmin)
68 fail("DisplayID payload length is less than expected (%d < %d).\n", len, expectedlenmin);
69 else
70 return true;
71
72 if (len > payloaddumpstart)
73 hex_block(" ", x + 3 + payloaddumpstart, len - payloaddumpstart);
74 return false;
75 }
76
77 // tag 0x00 and 0x20
78
parse_displayid_product_id(const unsigned char * x)79 void edid_state::parse_displayid_product_id(const unsigned char *x)
80 {
81 check_displayid_datablock_revision(x[1]);
82
83 dispid.has_product_identification = true;
84 if (dispid.version >= 0x20) {
85 unsigned oui = (x[3] << 16) | (x[4] << 8) | x[5];
86 printf(" Vendor OUI %s\n", ouitohex(oui).c_str());
87 } else {
88 printf(" Vendor ID: %c%c%c\n", x[3], x[4], x[5]);
89 }
90 printf(" Product Code: %u\n", x[6] | (x[7] << 8));
91 unsigned sn = x[8] | (x[9] << 8) | (x[10] << 16) | (x[11] << 24);
92 if (sn) {
93 if (hide_serial_numbers)
94 printf(" Serial Number: ...\n");
95 else
96 printf(" Serial Number: %u\n", sn);
97 }
98 unsigned week = x[12];
99 unsigned year = 2000 + x[13];
100 printf(" %s: %u",
101 week == 0xff ? "Model Year" : "Year of Manufacture", year);
102 if (week && week <= 0x36)
103 printf(", Week %u", week);
104 printf("\n");
105 if (x[14]) {
106 char buf[256];
107
108 memcpy(buf, x + 15, x[14]);
109 buf[x[14]] = 0;
110 printf(" Product ID: %s\n", buf);
111 }
112 }
113
114 // tag 0x01
115
116 static const char *feature_support_flags[] = {
117 "De-interlacing",
118 "Support ACP, ISRC1, or ISRC2packets",
119 "Fixed pixel format",
120 "Fixed timing",
121 "Power management (DPM)",
122 "Audio input override",
123 "Separate audio inputs provided",
124 "Audio support on video interface"
125 };
126
print_flag_lines(const char * indent,const char * label,unsigned char flag_byte,const char ** flags)127 static void print_flag_lines(const char *indent, const char *label,
128 unsigned char flag_byte, const char **flags)
129 {
130 if (flag_byte) {
131 printf("%s\n", label);
132
133 for (int i = 0; i < 8; i++)
134 if (flag_byte & (1 << i))
135 printf("%s%s\n", indent, flags[i]);
136 }
137 }
138
parse_displayid_parameters(const unsigned char * x)139 void edid_state::parse_displayid_parameters(const unsigned char *x)
140 {
141 check_displayid_datablock_revision(x[1]);
142
143 if (!check_displayid_datablock_length(x, 12, 12))
144 return;
145
146 dispid.has_display_parameters = true;
147 printf(" Image size: %.1f mm x %.1f mm\n",
148 ((x[4] << 8) + x[3]) / 10.0,
149 ((x[6] << 8) + x[5]) / 10.0);
150 printf(" Pixels: %d x %d\n",
151 (x[8] << 8) + x[7], (x[10] << 8) + x[9]);
152 print_flag_lines(" ", " Feature support flags:",
153 x[11], feature_support_flags);
154
155 if (x[12] != 0xff)
156 printf(" Gamma: %.2f\n", ((x[12] + 100.0) / 100.0));
157 printf(" Aspect ratio: %.2f\n", ((x[13] + 100.0) / 100.0));
158 printf(" Dynamic bpc native: %d\n", (x[14] & 0xf) + 1);
159 printf(" Dynamic bpc overall: %d\n", ((x[14] >> 4) & 0xf) + 1);
160 }
161
162 // tag 0x02
163
164 static const char *std_colorspace_ids[] = {
165 "sRGB",
166 "BT.601",
167 "BT.709",
168 "Adobe RGB",
169 "DCI-P3",
170 "NTSC",
171 "EBU",
172 "Adobe Wide Gamut RGB",
173 "DICOM"
174 };
175
fp2d(unsigned short fp)176 static double fp2d(unsigned short fp)
177 {
178 return fp / 4096.0;
179 }
180
parse_displayid_color_characteristics(const unsigned char * x)181 void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
182 {
183 check_displayid_datablock_revision(x[1], 0xf8, 1);
184
185 unsigned cie_year = (x[1] & 0x80) ? 1976 : 1931;
186 unsigned xfer_id = (x[1] >> 3) & 0x0f;
187 unsigned num_whitepoints = x[3] & 0x0f;
188 unsigned num_primaries = (x[3] >> 4) & 0x07;
189 bool temporal_color = x[3] & 0x80;
190 unsigned offset = 4;
191
192 printf(" Uses %s color\n", temporal_color ? "temporal" : "spatial");
193 printf(" Uses %u CIE (x, y) coordinates\n", cie_year);
194 if (xfer_id) {
195 printf(" Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id);
196 if (!(dispid.preparsed_xfer_ids & (1 << xfer_id)))
197 fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id);
198 }
199 if (!num_primaries) {
200 printf(" Uses color space %s\n",
201 x[4] >= ARRAY_SIZE(std_colorspace_ids) ? "Reserved" :
202 std_colorspace_ids[x[4]]);
203 offset++;
204 }
205 for (unsigned i = 0; i < num_primaries; i++) {
206 unsigned idx = offset + 3 * i;
207
208 printf(" Primary #%u: (%.4f, %.4f)\n", i,
209 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
210 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
211 }
212 offset += 3 * num_primaries;
213 for (unsigned i = 0; i < num_whitepoints; i++) {
214 unsigned idx = offset + 3 * i;
215
216 printf(" White point #%u: (%.4f, %.4f)\n", i,
217 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
218 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
219 }
220 }
221
222 // tag 0x03 and 0x22
223
parse_displayid_type_1_7_timing(const unsigned char * x,bool type7,unsigned block_rev,bool is_cta)224 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
225 bool type7, unsigned block_rev, bool is_cta)
226 {
227 struct timings t = {};
228 unsigned hbl, vbl;
229 std::string s("aspect ");
230
231 dispid.has_type_1_7 = true;
232 t.pixclk_khz = (type7 ? 1 : 10) * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
233 switch (x[3] & 0xf) {
234 case 0:
235 s += "1:1";
236 t.hratio = t.vratio = 1;
237 break;
238 case 1:
239 s += "5:4";
240 t.hratio = 5;
241 t.vratio = 4;
242 break;
243 case 2:
244 s += "4:3";
245 t.hratio = 4;
246 t.vratio = 3;
247 break;
248 case 3:
249 s += "15:9";
250 t.hratio = 15;
251 t.vratio = 9;
252 break;
253 case 4:
254 s += "16:9";
255 t.hratio = 16;
256 t.vratio = 9;
257 break;
258 case 5:
259 s += "16:10";
260 t.hratio = 16;
261 t.vratio = 10;
262 break;
263 case 6:
264 s += "64:27";
265 t.hratio = 64;
266 t.vratio = 27;
267 break;
268 case 7:
269 s += "256:135";
270 t.hratio = 256;
271 t.vratio = 135;
272 break;
273 default:
274 s += "undefined";
275 if ((x[3] & 0xf) > (dispid.version <= 0x12 ? 7 : 8))
276 fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
277 break;
278 }
279 switch ((x[3] >> 5) & 0x3) {
280 case 0:
281 s += ", no 3D stereo";
282 break;
283 case 1:
284 s += ", 3D stereo";
285 break;
286 case 2:
287 s += ", 3D stereo depends on user action";
288 break;
289 case 3:
290 s += ", reserved";
291 fail("Reserved stereo 0x03.\n");
292 break;
293 }
294 if (block_rev >= 2 && (x[3] & 0x80))
295 s += ", YCbCr 4:2:0";
296
297 t.hact = 1 + (x[4] | (x[5] << 8));
298 hbl = 1 + (x[6] | (x[7] << 8));
299 t.hfp = 1 + (x[8] | ((x[9] & 0x7f) << 8));
300 t.hsync = 1 + (x[10] | (x[11] << 8));
301 t.hbp = hbl - t.hfp - t.hsync;
302 if ((x[9] >> 7) & 0x1)
303 t.pos_pol_hsync = true;
304 t.vact = 1 + (x[12] | (x[13] << 8));
305 vbl = 1 + (x[14] | (x[15] << 8));
306 t.vfp = 1 + (x[16] | ((x[17] & 0x7f) << 8));
307 t.vsync = 1 + (x[18] | (x[19] << 8));
308 t.vbp = vbl - t.vfp - t.vsync;
309 if ((x[17] >> 7) & 0x1)
310 t.pos_pol_vsync = true;
311
312 if (x[3] & 0x10) {
313 t.interlaced = true;
314 t.vfp /= 2;
315 t.vsync /= 2;
316 t.vbp /= 2;
317 }
318 if (block_rev < 2 && (x[3] & 0x80)) {
319 s += ", preferred";
320 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
321 }
322
323 print_timings(" ", &t, "DTD", s.c_str(), true);
324 if (is_cta) {
325 timings_ext te(t, "DTD", s);
326 cta.vec_vtdbs.push_back(te);
327
328 // Only use a T7VTDB if is cannot be expressed by a
329 // DTD or a T10VTDB.
330 if (t.hact <= 4095 && t.vact <= 4095 &&
331 t.pixclk_khz <= 655360 && !(x[3] & 0xe0)) {
332 fail("This T7VTDB can be represented as an 18-byte DTD.\n");
333 return;
334 }
335 unsigned htot = t.hact + t.hfp + t.hsync + t.hbp;
336 unsigned vtot = t.vact + t.vfp + t.vsync + t.vbp;
337 unsigned refresh = (t.pixclk_khz * 1000ULL) / (htot * vtot);
338
339 for (unsigned rb = RB_NONE; rb <= RB_CVT_V3; rb++) {
340 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, rb);
341 if (match_timings(t, cvt_t)) {
342 fail("This T7VTDB can be represented as a T10VTDB.\n");
343 return;
344 }
345 }
346 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, RB_CVT_V3,
347 false, false, true);
348 if (match_timings(t, cvt_t))
349 fail("This T7VTDB can be represented as a T10VTDB.\n");
350 }
351 }
352
353 // tag 0x04
354
parse_displayid_type_2_timing(const unsigned char * x)355 void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
356 {
357 struct timings t = {};
358 unsigned hbl, vbl;
359 std::string s("aspect ");
360
361 t.pixclk_khz = 10 * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
362 t.hact = 8 + 8 * (x[4] | ((x[5] & 0x01) << 8));
363 hbl = 8 + 8 * ((x[5] & 0xfe) >> 1);
364 t.hfp = 8 + 8 * ((x[6] & 0xf0) >> 4);
365 t.hsync = 8 + 8 * (x[6] & 0xf);
366 t.hbp = hbl - t.hfp - t.hsync;
367 if ((x[3] >> 3) & 0x1)
368 t.pos_pol_hsync = true;
369 t.vact = 1 + (x[7] | ((x[8] & 0xf) << 8));
370 vbl = 1 + x[9];
371 t.vfp = 1 + (x[10] >> 4);
372 t.vsync = 1 + (x[10] & 0xf);
373 t.vbp = vbl - t.vfp - t.vsync;
374 if ((x[17] >> 2) & 0x1)
375 t.pos_pol_vsync = true;
376
377 if (x[3] & 0x10) {
378 t.interlaced = true;
379 t.vfp /= 2;
380 t.vsync /= 2;
381 t.vbp /= 2;
382 }
383
384 calc_ratio(&t);
385
386 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
387
388 switch ((x[3] >> 5) & 0x3) {
389 case 0:
390 s += ", no 3D stereo";
391 break;
392 case 1:
393 s += ", 3D stereo";
394 break;
395 case 2:
396 s += ", 3D stereo depends on user action";
397 break;
398 case 3:
399 s += ", reserved";
400 fail("Reserved stereo 0x03.\n");
401 break;
402 }
403 if (x[3] & 0x80) {
404 s += ", preferred";
405 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
406 }
407
408 print_timings(" ", &t, "DTD", s.c_str(), true);
409 }
410
411 // tag 0x05
412
parse_displayid_type_3_timing(const unsigned char * x)413 void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
414 {
415 struct timings t = {};
416 std::string s("aspect ");
417
418 switch (x[0] & 0xf) {
419 case 0:
420 s += "1:1";
421 t.hratio = t.vratio = 1;
422 break;
423 case 1:
424 s += "5:4";
425 t.hratio = 5;
426 t.vratio = 4;
427 break;
428 case 2:
429 s += "4:3";
430 t.hratio = 4;
431 t.vratio = 3;
432 break;
433 case 3:
434 s += "15:9";
435 t.hratio = 15;
436 t.vratio = 9;
437 break;
438 case 4:
439 s += "16:9";
440 t.hratio = 16;
441 t.vratio = 9;
442 break;
443 case 5:
444 s += "16:10";
445 t.hratio = 16;
446 t.vratio = 10;
447 break;
448 case 6:
449 s += "64:27";
450 t.hratio = 64;
451 t.vratio = 27;
452 break;
453 case 7:
454 s += "256:135";
455 t.hratio = 256;
456 t.vratio = 135;
457 break;
458 default:
459 s += "undefined";
460 if ((x[3] & 0xf) > (dispid.version <= 0x12 ? 7 : 8))
461 fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
462 break;
463 }
464
465 t.rb = ((x[0] & 0x70) >> 4) == 1 ? RB_CVT_V1 : RB_NONE;
466 t.hact = 8 + 8 * x[1];
467 t.vact = t.hact * t.vratio / t.hratio;
468
469 edid_cvt_mode(1 + (x[2] & 0x7f), t);
470
471 if (x[0] & 0x80) {
472 s += ", preferred";
473 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
474 }
475
476 print_timings(" ", &t, "CVT", s.c_str());
477 }
478
479 // tag 0x06 and 0x23
480
parse_displayid_type_4_8_timing(unsigned char type,unsigned short id,bool is_cta)481 void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
482 {
483 const struct timings *t = NULL;
484 char type_name[16];
485
486 switch (type) {
487 case 0: t = find_dmt_id(id); sprintf(type_name, "DMT 0x%02x", id); break;
488 case 1: t = find_vic_id(id); sprintf(type_name, "VIC %3u", id); break;
489 case 2: t = find_hdmi_vic_id(id); sprintf(type_name, "HDMI VIC %u", id); break;
490 default: break;
491 }
492 if (t)
493 print_timings(" ", t, type_name);
494 if (t && is_cta && !cta.t8vtdb.is_valid()) {
495 timings_ext te(*t, type_name, "");
496 cta.t8vtdb = te;
497 }
498 }
499
500 // tag 0x09
501
parse_displayid_video_timing_range_limits(const unsigned char * x)502 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x)
503 {
504 check_displayid_datablock_revision(x[1]);
505
506 if (!check_displayid_datablock_length(x, 15, 15))
507 return;
508 printf(" Pixel Clock: %.3f-%.3f MHz\n",
509 (double)((x[3] | (x[4] << 8) | (x[5] << 16)) + 1) / 100.0,
510 (double)((x[6] | (x[7] << 8) | (x[8] << 16)) + 1) / 100.0);
511 printf(" Horizontal Frequency: %u-%u kHz\n", x[9], x[10]);
512 printf(" Minimum Horizontal Blanking: %u pixels\n", x[11] | (x[12] << 8));
513 printf(" Vertical Refresh: %u-%u Hz\n", x[13], x[14]);
514 printf(" Minimum Vertical Blanking: %u lines\n", x[15] | (x[16] << 8));
515 if (x[17] & 0x80)
516 printf(" Supports Interlaced\n");
517 if (x[17] & 0x40)
518 printf(" Supports CVT\n");
519 if (x[17] & 0x20)
520 printf(" Supports CVT Reduced Blanking\n");
521 if (x[17] & 0x10)
522 printf(" Discrete frequency display device\n");
523 }
524
525 // tag 0x0a and 0x0b
526
parse_displayid_string(const unsigned char * x)527 void edid_state::parse_displayid_string(const unsigned char *x)
528 {
529 check_displayid_datablock_revision(x[1]);
530 if (check_displayid_datablock_length(x))
531 printf(" Text: '%s'\n", extract_string(x + 3, x[2]));
532 }
533
534 // tag 0x0c
535
parse_displayid_display_device(const unsigned char * x)536 void edid_state::parse_displayid_display_device(const unsigned char *x)
537 {
538 check_displayid_datablock_revision(x[1]);
539
540 if (!check_displayid_datablock_length(x, 13, 13))
541 return;
542
543 printf(" Display Device Technology: ");
544 switch (x[3]) {
545 case 0x00: printf("Monochrome CRT\n"); break;
546 case 0x01: printf("Standard tricolor CRT\n"); break;
547 case 0x02: printf("Other/undefined CRT\n"); break;
548 case 0x10: printf("Passive matrix TN\n"); break;
549 case 0x11: printf("Passive matrix cholesteric LC\n"); break;
550 case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
551 case 0x13: printf("Other passive matrix LC type\n"); break;
552 case 0x14: printf("Active-matrix TN\n"); break;
553 case 0x15: printf("Active-matrix IPS (all types)\n"); break;
554 case 0x16: printf("Active-matrix VA (all types)\n"); break;
555 case 0x17: printf("Active-matrix OCB\n"); break;
556 case 0x18: printf("Active-matrix ferroelectric\n"); break;
557 case 0x1f: printf("Other LC type\n"); break;
558 case 0x20: printf("DC plasma\n"); break;
559 case 0x21: printf("AC plasma\n"); break;
560 }
561 switch (x[3] & 0xf0) {
562 case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
563 case 0x40: printf("Inorganic LED\n"); break;
564 case 0x50: printf("Organic LED/OEL\n"); break;
565 case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
566 case 0x70: printf("Electrophoretic\n"); break;
567 case 0x80: printf("Electrochromic\n"); break;
568 case 0x90: printf("Electromechanical\n"); break;
569 case 0xa0: printf("Electrowetting\n"); break;
570 case 0xf0: printf("Other type not defined here\n"); break;
571 }
572 printf(" Display operating mode: ");
573 switch (x[4] >> 4) {
574 case 0x00: printf("Direct-view reflective, ambient light\n"); break;
575 case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
576 case 0x02: printf("Direct-view reflective, uses light source\n"); break;
577 case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
578 case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
579 case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
580 case 0x06: printf("Direct-view emissive\n"); break;
581 case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
582 case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
583 case 0x09: printf("Transparent display, ambient light\n"); break;
584 case 0x0a: printf("Transparent emissive display\n"); break;
585 case 0x0b: printf("Projection device using reflective light modulator\n"); break;
586 case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
587 case 0x0d: printf("Projection device using emissive image transducer\n"); break;
588 default: printf("Reserved\n"); break;
589 }
590 if (x[4] & 0x08)
591 printf(" The backlight may be switched on and off\n");
592 if (x[4] & 0x04)
593 printf(" The backlight's intensity can be controlled\n");
594 unsigned w = x[5] | (x[6] << 8);
595 unsigned h = x[7] | (x[8] << 8);
596 if (w && h) {
597 printf(" Display native pixel format: %ux%u\n", w + 1, h + 1);
598 dispid.native_width = w + 1;
599 dispid.native_height = h + 1;
600 } else if (w || h) {
601 fail("Invalid Native Pixel Format %ux%u.\n", w, h);
602 }
603 printf(" Aspect ratio and orientation:\n");
604 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
605 unsigned char v = x[0x0a];
606 printf(" Default Orientation: ");
607 switch ((v & 0xc0) >> 6) {
608 case 0x00: printf("Landscape\n"); break;
609 case 0x01: printf("Portrait\n"); break;
610 case 0x02: printf("Not Fixed\n"); break;
611 case 0x03: printf("Undefined\n"); break;
612 }
613 printf(" Rotation Capability: ");
614 switch ((v & 0x30) >> 4) {
615 case 0x00: printf("None\n"); break;
616 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
617 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
618 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
619 }
620 printf(" Zero Pixel Location: ");
621 switch ((v & 0x0c) >> 2) {
622 case 0x00: printf("Upper Left\n"); break;
623 case 0x01: printf("Upper Right\n"); break;
624 case 0x02: printf("Lower Left\n"); break;
625 case 0x03: printf("Lower Right\n"); break;
626 }
627 printf(" Scan Direction: ");
628 switch (v & 0x03) {
629 case 0x00: printf("Not defined\n"); break;
630 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
631 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
632 case 0x03: printf("Reserved\n");
633 fail("Scan Direction used the reserved value 0x03.\n");
634 break;
635 }
636 printf(" Sub-pixel layout/configuration/shape: ");
637 switch (x[0x0b]) {
638 case 0x00: printf("Not defined\n"); break;
639 case 0x01: printf("RGB vertical stripes\n"); break;
640 case 0x02: printf("RGB horizontal stripes\n"); break;
641 case 0x03: printf("Vertical stripes using primary order\n"); break;
642 case 0x04: printf("Horizontal stripes using primary order\n"); break;
643 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
644 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
645 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
646 case 0x08: printf("Mosaic\n"); break;
647 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
648 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
649 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
650 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
651 default: printf("Reserved\n"); break;
652 }
653 printf(" Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
654 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
655 printf(" Color bit depth: %u\n", x[0x0e] & 0x0f);
656 v = x[0x0f];
657 printf(" Response time for %s transition: %u ms\n",
658 (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f);
659 }
660
661 // tag 0x0d
662
parse_displayid_intf_power_sequencing(const unsigned char * x)663 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x)
664 {
665 check_displayid_datablock_revision(x[1]);
666
667 if (!check_displayid_datablock_length(x, 6, 6))
668 return;
669
670 printf(" Power Sequence T1 Range: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2);
671 printf(" Power Sequence T2 Range: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2);
672 printf(" Power Sequence T3 Range: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2);
673 printf(" Power Sequence T4 Min: %u.0 ms\n", (x[6] & 0x7f) * 10);
674 printf(" Power Sequence T5 Min: %u.0 ms\n", (x[7] & 0x3f) * 10);
675 printf(" Power Sequence T6 Min: %u.0 ms\n", (x[8] & 0x3f) * 10);
676 }
677
678 // tag 0x0e
679
parse_displayid_transfer_characteristics(const unsigned char * x)680 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x)
681 {
682 check_displayid_datablock_revision(x[1], 0xf0, 1);
683
684 unsigned xfer_id = x[1] >> 4;
685 bool first_is_white = x[3] & 0x80;
686 bool four_param = x[3] & 0x20;
687
688 if (xfer_id) {
689 printf(" Transfer Characteristics Data Block Identifier: %u\n", xfer_id);
690 if (!(dispid.preparsed_color_ids & (1 << xfer_id)))
691 fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id);
692 }
693 if (first_is_white)
694 printf(" The first curve is the 'white' transfer characteristic\n");
695 if (x[3] & 0x40)
696 printf(" Individual response curves\n");
697
698 unsigned offset = 4;
699 unsigned len = x[2] - 1;
700
701 for (unsigned i = 0; len; i++) {
702 if ((x[3] & 0x80) && !i)
703 printf(" White curve: ");
704 else
705 printf(" Response curve #%u:",
706 i - first_is_white);
707 unsigned samples = x[offset];
708 if (four_param) {
709 if (samples != 5)
710 fail("Expected 5 samples.\n");
711 printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
712 x[offset + 1], x[offset + 2], x[offset + 3], x[offset + 4],
713 (double)(x[offset + 5] + 100.0) / 100.0);
714 samples++;
715 } else {
716 double sum = 0;
717
718 // The spec is not very clear about the number of samples:
719 // should this be interpreted as the actual number of
720 // samples stored in this Data Block, or as the number of
721 // samples in the curve, but where the last sample is not
722 // actually stored since it is always 0x3ff.
723 //
724 // The ATP Manager interprets this as the latter, so that's
725 // what we implement here.
726 for (unsigned j = offset + 1; j < offset + samples; j++) {
727 sum += x[j];
728 printf(" %.2f", sum * 100.0 / 1023.0);
729 }
730 printf(" 100.00\n");
731 }
732 offset += samples;
733 len -= samples;
734 }
735 }
736
737 // tag 0x0f
738
parse_displayid_display_intf(const unsigned char * x)739 void edid_state::parse_displayid_display_intf(const unsigned char *x)
740 {
741 check_displayid_datablock_revision(x[1]);
742
743 if (!check_displayid_datablock_length(x, 10, 10))
744 return;
745
746 dispid.has_display_interface_features = true;
747 printf(" Interface Type: ");
748 switch (x[3] >> 4) {
749 case 0x00:
750 switch (x[3] & 0xf) {
751 case 0x00: printf("Analog 15HD/VGA\n"); break;
752 case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
753 case 0x02: printf("Analog VESA NAVI-D\n"); break;
754 default: printf("Reserved\n"); break;
755 }
756 break;
757 case 0x01: printf("LVDS\n"); break;
758 case 0x02: printf("TMDS\n"); break;
759 case 0x03: printf("RSDS\n"); break;
760 case 0x04: printf("DVI-D\n"); break;
761 case 0x05: printf("DVI-I, analog\n"); break;
762 case 0x06: printf("DVI-I, digital\n"); break;
763 case 0x07: printf("HDMI-A\n"); break;
764 case 0x08: printf("HDMI-B\n"); break;
765 case 0x09: printf("MDDI\n"); break;
766 case 0x0a: printf("DisplayPort\n"); break;
767 case 0x0b: printf("Proprietary Digital Interface\n"); break;
768 default: printf("Reserved\n"); break;
769 }
770 if (x[3] >> 4)
771 printf(" Number of Links: %u\n", x[3] & 0xf);
772 printf(" Interface Standard Version: %u.%u\n",
773 x[4] >> 4, x[4] & 0xf);
774 print_flags(" Supported bpc for RGB encoding", x[5], bpc444);
775 print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444);
776 print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx);
777 printf(" Supported Content Protection: ");
778 switch (x[8] & 0xf) {
779 case 0x00: printf("None\n"); break;
780 case 0x01: printf("HDCP "); break;
781 case 0x02: printf("DTCP "); break;
782 case 0x03: printf("DPCP "); break;
783 default: printf("Reserved "); break;
784 }
785 if (x[8] & 0xf)
786 printf("%u.%u\n", x[9] >> 4, x[9] & 0xf);
787 unsigned char v = x[0x0a] & 0xf;
788 printf(" Spread Spectrum: ");
789 switch (x[0x0a] >> 6) {
790 case 0x00: printf("None\n"); break;
791 case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break;
792 case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break;
793 case 0x03: printf("Reserved\n"); break;
794 }
795 switch (x[3] >> 4) {
796 case 0x01:
797 printf(" LVDS Color Mapping: %s mode\n",
798 (x[0x0b] & 0x10) ? "6 bit compatible" : "normal");
799 if (x[0x0b] & 0x08) printf(" LVDS supports 2.8V\n");
800 if (x[0x0b] & 0x04) printf(" LVDS supports 12V\n");
801 if (x[0x0b] & 0x02) printf(" LVDS supports 5V\n");
802 if (x[0x0b] & 0x01) printf(" LVDS supports 3.3V\n");
803 printf(" LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE");
804 if (x[0x0c] & 0x04)
805 printf(" LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High");
806 else
807 printf(" LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High");
808 printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling");
809 break;
810 case 0x0b:
811 printf(" PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE");
812 if (x[0x0b] & 0x04)
813 printf(" PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High");
814 else
815 printf(" PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High");
816 printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling");
817 break;
818 }
819 }
820
821 // tag 0x10 and 0x27
822
parse_displayid_stereo_display_intf(const unsigned char * x)823 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x)
824 {
825 check_displayid_datablock_revision(x[1], 0xc0, 1);
826
827 switch (x[1] >> 6) {
828 case 0x00: printf(" Timings that explicitly report 3D capability\n"); break;
829 case 0x01: printf(" Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
830 case 0x02: printf(" All listed timings\n"); break;
831 case 0x03: printf(" Only Timings Codes listed here\n"); break;
832 }
833
834 unsigned len = x[2];
835
836 switch (x[4]) {
837 case 0x00:
838 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
839 (x[5] & 1) ? "0/1" : "1/0");
840 break;
841 case 0x01:
842 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
843 (x[5] & 1) ? "Right" : "Left");
844 break;
845 case 0x02:
846 printf(" Pixel Interleaved Stereo:\n");
847 for (unsigned y = 0; y < 8; y++) {
848 unsigned char v = x[5 + y];
849
850 printf(" ");
851 for (int x = 7; x >= 0; x--)
852 printf("%c", (v & (1 << x)) ? 'L' : 'R');
853 printf("\n");
854 }
855 break;
856 case 0x03:
857 printf(" Dual Interface, Left and Right Separate\n");
858 printf(" Carries the %s-eye view\n",
859 (x[5] & 1) ? "Right" : "Left");
860 printf(" ");
861 switch ((x[5] >> 1) & 3) {
862 case 0x00: printf("No mirroring\n"); break;
863 case 0x01: printf("Left/Right mirroring\n"); break;
864 case 0x02: printf("Top/Bottom mirroring\n"); break;
865 case 0x03: printf("Reserved\n"); break;
866 }
867 break;
868 case 0x04:
869 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
870 x[5], x[6]);
871 break;
872 case 0x05:
873 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
874 (x[5] & 1) ? "Right" : "Left");
875 break;
876 case 0xff:
877 printf(" Proprietary\n");
878 break;
879 default:
880 printf(" Reserved\n");
881 break;
882 }
883 if (!(x[1] & 0x40)) // Has No Timing Codes
884 return;
885 len -= 1 + x[3];
886 x += 4 + x[3];
887 while (1U + (x[0] & 0x1f) <= len) {
888 unsigned num_codes = x[0] & 0x1f;
889 unsigned type = x[0] >> 6;
890 char type_name[16];
891
892 for (unsigned i = 1; i <= num_codes; i++) {
893 switch (type) {
894 case 0x00:
895 sprintf(type_name, "DMT 0x%02x", x[i]);
896 print_timings(" ", find_dmt_id(x[i]), type_name);
897 break;
898 case 0x01:
899 sprintf(type_name, "VIC %3u", x[i]);
900 print_timings(" ", find_vic_id(x[i]), type_name);
901 break;
902 case 0x02:
903 sprintf(type_name, "HDMI VIC %u", x[i]);
904 print_timings(" ", find_hdmi_vic_id(x[i]), type_name);
905 break;
906 }
907 }
908
909 len -= 1 + num_codes;
910 x += 1 + num_codes;
911 }
912 }
913
914 // tag 0x11
915
parse_displayid_type_5_timing(const unsigned char * x)916 void edid_state::parse_displayid_type_5_timing(const unsigned char *x)
917 {
918 struct timings t = {};
919 std::string s("aspect ");
920
921 t.hact = 1 + (x[2] | (x[3] << 8));
922 t.vact = 1 + (x[4] | (x[5] << 8));
923 calc_ratio(&t);
924 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
925 switch ((x[0] >> 5) & 0x3) {
926 case 0:
927 s += ", no 3D stereo";
928 break;
929 case 1:
930 s += ", 3D stereo";
931 break;
932 case 2:
933 s += ", 3D stereo depends on user action";
934 break;
935 case 3:
936 s += ", reserved";
937 fail("Reserved stereo 0x03.\n");
938 break;
939 }
940 if (x[0] & 0x10)
941 s += ", refresh rate * (1000/1001) supported";
942
943 t.rb = RB_CVT_V2;
944 if ((x[0] & 0x03) == 1)
945 warn("Unexpected use of 'custom reduced blanking'.\n");
946 else if ((x[0] & 0x03) > 1)
947 fail("Invalid Timing Formula.\n");
948
949 edid_cvt_mode(1 + x[6], t);
950
951 if (x[0] & 0x80) {
952 s += ", preferred";
953 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
954 }
955
956 print_timings(" ", &t, "CVT", s.c_str());
957 }
958
959 // tag 0x12 and 0x28
960
parse_displayid_tiled_display_topology(const unsigned char * x,bool is_v2)961 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2)
962 {
963 check_displayid_datablock_revision(x[1]);
964
965 if (!check_displayid_datablock_length(x, 22, 22))
966 return;
967
968 unsigned caps = x[3];
969 unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30);
970 unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30);
971 unsigned tile_v_location = (x[5] & 0xf) | ((x[6] & 0x3) << 4);
972 unsigned tile_h_location = (x[5] >> 4) | (((x[6] >> 2) & 0x3) << 4);
973 unsigned tile_width = x[7] | (x[8] << 8);
974 unsigned tile_height = x[9] | (x[10] << 8);
975 unsigned pix_mult = x[11];
976
977 printf(" Capabilities:\n");
978 printf(" Behavior if it is the only tile: ");
979 switch (caps & 0x07) {
980 case 0x00: printf("Undefined\n"); break;
981 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
982 case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
983 case 0x03: printf("Image is cloned to all other tiles\n"); break;
984 default: printf("Reserved\n"); break;
985 }
986 printf(" Behavior if more than one tile and fewer than total number of tiles: ");
987 switch ((caps >> 3) & 0x03) {
988 case 0x00: printf("Undefined\n"); break;
989 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
990 default: printf("Reserved\n"); break;
991 }
992 if (caps & 0x80)
993 printf(" Tiled display consists of a single physical display enclosure\n");
994 else
995 printf(" Tiled display consists of multiple physical display enclosures\n");
996 printf(" Num horizontal tiles: %u Num vertical tiles: %u\n",
997 num_h_tile + 1, num_v_tile + 1);
998 printf(" Tile location: %u, %u\n", tile_h_location, tile_v_location);
999 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1000 if (caps & 0x40) {
1001 if (pix_mult) {
1002 printf(" Top bevel size: %.1f pixels\n",
1003 pix_mult * x[12] / 10.0);
1004 printf(" Bottom bevel size: %.1f pixels\n",
1005 pix_mult * x[13] / 10.0);
1006 printf(" Right bevel size: %.1f pixels\n",
1007 pix_mult * x[14] / 10.0);
1008 printf(" Left bevel size: %.1f pixels\n",
1009 pix_mult * x[15] / 10.0);
1010 } else {
1011 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1012 }
1013 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1014 } else if (pix_mult) {
1015 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1016 }
1017 if (is_v2)
1018 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1019 x[0x10], x[0x11], x[0x12]);
1020 else
1021 printf(" Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1022 x[0x10], x[0x11], x[0x12]);
1023 printf(" Tiled Display Product ID Code: %u\n",
1024 x[0x13] | (x[0x14] << 8));
1025 if (hide_serial_numbers)
1026 printf(" Tiled Display Serial Number: ...\n");
1027 else
1028 printf(" Tiled Display Serial Number: %u\n",
1029 x[0x15] | (x[0x16] << 8) | (x[0x17] << 16)| (x[0x18] << 24));
1030 }
1031
1032 // tag 0x13
1033
parse_displayid_type_6_timing(const unsigned char * x)1034 void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
1035 {
1036 struct timings t = {};
1037 std::string s("aspect ");
1038
1039 t.pixclk_khz = 1 + (x[0] + (x[1] << 8) + ((x[2] & 0x3f) << 16));
1040 t.hact = 1 + (x[3] | ((x[4] & 0x3f) << 8));
1041 if ((x[4] >> 7) & 0x1)
1042 t.pos_pol_hsync = true;
1043 unsigned hbl = 1 + (x[7] | ((x[9] & 0xf) << 8));
1044 t.hfp = 1 + (x[8] | ((x[9] & 0xf0) << 4));
1045 t.hsync = 1 + x[10];
1046 t.hbp = hbl - t.hfp - t.hsync;
1047 t.vact = 1 + (x[5] | ((x[6] & 0x3f) << 8));
1048 if ((x[6] >> 7) & 0x1)
1049 t.pos_pol_vsync = true;
1050 unsigned vbl = 1 + x[11];
1051 t.vfp = 1 + x[12];
1052 t.vsync = 1 + (x[13] & 0x0f);
1053 t.vbp = vbl - t.vfp - t.vsync;
1054
1055 if (x[13] & 0x80) {
1056 t.interlaced = true;
1057 t.vfp /= 2;
1058 t.vsync /= 2;
1059 t.vbp /= 2;
1060 }
1061 calc_ratio(&t);
1062 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1063 if (x[2] & 0x40) {
1064 double aspect_mult = x[14] * 3.0 / 256.0;
1065 unsigned size_mult = 1 + (x[16] >> 4);
1066
1067 t.vsize_mm = size_mult * (1 + (x[15] | ((x[16] & 0xf) << 8)));
1068 t.hsize_mm = t.vsize_mm * aspect_mult;
1069 }
1070
1071 switch ((x[13] >> 5) & 0x3) {
1072 case 0:
1073 s += ", no 3D stereo";
1074 break;
1075 case 1:
1076 s += ", 3D stereo";
1077 break;
1078 case 2:
1079 s += ", 3D stereo depends on user action";
1080 break;
1081 case 3:
1082 s += ", reserved";
1083 fail("Reserved stereo 0x03.\n");
1084 break;
1085 }
1086
1087 if (x[2] & 0x80) {
1088 s += ", preferred";
1089 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
1090 }
1091
1092 print_timings(" ", &t, "DTD", s.c_str(), true);
1093 }
1094
ieee7542d(unsigned short fp)1095 static std::string ieee7542d(unsigned short fp)
1096 {
1097 int exp = ((fp & 0x7c00) >> 10) - 15;
1098 unsigned fract = (fp & 0x3ff) | 0x400;
1099
1100 if (fp == 0x8000)
1101 return "do not use";
1102 if (fp & 0x8000)
1103 return "reserved";
1104 return std::to_string(pow(2, exp) * fract / 1024.0) + " cd/m^2";
1105 }
1106
1107 // tag 0x21
1108
parse_displayid_parameters_v2(const unsigned char * x,unsigned block_rev)1109 void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
1110 unsigned block_rev)
1111 {
1112 if (!check_displayid_datablock_length(x, 29, 29))
1113 return;
1114
1115 unsigned hor_size = (x[4] << 8) + x[3];
1116 unsigned vert_size = (x[6] << 8) + x[5];
1117
1118 dispid.has_display_parameters = true;
1119 if (x[1] & 0x80)
1120 printf(" Image size: %u mm x %u mm\n",
1121 hor_size, vert_size);
1122 else
1123 printf(" Image size: %.1f mm x %.1f mm\n",
1124 hor_size / 10.0, vert_size / 10.0);
1125 unsigned w = (x[8] << 8) + x[7];
1126 unsigned h = (x[10] << 8) + x[9];
1127 if (w && h) {
1128 printf(" Native Format: %ux%u\n", w, h);
1129 dispid.native_width = w;
1130 dispid.native_height = h;
1131 } else if (w || h) {
1132 fail("Invalid Native Format %ux%u.\n", w, h);
1133 }
1134 unsigned char v = x[11];
1135 printf(" Scan Orientation: ");
1136 switch (v & 0x07) {
1137 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1138 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1139 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1140 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1141 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1142 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1143 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1144 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1145 }
1146 printf(" Luminance Information: ");
1147 switch ((v >> 3) & 0x03) {
1148 case 0x00: printf("Minimum guaranteed value\n"); break;
1149 case 0x01: printf("Guidance for the Source device\n"); break;
1150 default: printf("Reserved\n"); break;
1151 }
1152 printf(" Color Information: CIE %u\n",
1153 (v & 0x40) ? 1976 : 1931);
1154 printf(" Audio Speaker Information: %sintegrated\n",
1155 (v & 0x80) ? "not " : "");
1156 printf(" Native Color Chromaticity:\n");
1157 printf(" Primary #1: (%.6f, %.6f)\n",
1158 fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1159 fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1160 printf(" Primary #2: (%.6f, %.6f)\n",
1161 fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1162 fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1163 printf(" Primary #3: (%.6f, %.6f)\n",
1164 fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1165 fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1166 printf(" White Point: (%.6f, %.6f)\n",
1167 fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1168 fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1169 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1170 ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1171 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1172 ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1173 printf(" Native Minimum Luminance: %s\n",
1174 ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1175 printf(" Native Color Depth: ");
1176 if (!(x[0x1e] & 0x07))
1177 printf("Not defined\n");
1178 else if (bpc444[x[0x1e] & 0x07])
1179 printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1180 else
1181 printf("Reserved\n");
1182 printf(" Display Device Technology: ");
1183 switch ((x[0x1e] >> 4) & 0x07) {
1184 case 0x00: printf("Not Specified\n"); break;
1185 case 0x01: printf("Active Matrix LCD\n"); break;
1186 case 0x02: printf("Organic LED\n"); break;
1187 default: printf("Reserved\n"); break;
1188 }
1189 if (block_rev)
1190 printf(" Display Device Theme Preference: %s\n",
1191 (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1192 if (x[0x1f] != 0xff)
1193 printf(" Native Gamma EOTF: %.2f\n",
1194 (100 + x[0x1f]) / 100.0);
1195 }
1196
1197 // tag 0x24
1198
parse_displayid_type_9_timing(const unsigned char * x)1199 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1200 {
1201 struct timings t = {};
1202 std::string s("aspect ");
1203
1204 t.hact = 1 + (x[1] | (x[2] << 8));
1205 t.vact = 1 + (x[3] | (x[4] << 8));
1206 calc_ratio(&t);
1207 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1208 switch ((x[0] >> 5) & 0x3) {
1209 case 0:
1210 s += ", no 3D stereo";
1211 break;
1212 case 1:
1213 s += ", 3D stereo";
1214 break;
1215 case 2:
1216 s += ", 3D stereo depends on user action";
1217 break;
1218 case 3:
1219 s += ", reserved";
1220 fail("Reserved stereo 0x03.\n");
1221 break;
1222 }
1223 if (x[0] & 0x10)
1224 s += ", refresh rate * (1000/1001) supported";
1225
1226 switch (x[0] & 0x07) {
1227 case 1: t.rb = RB_CVT_V1; break;
1228 case 2: t.rb = RB_CVT_V2; break;
1229 default: break;
1230 }
1231
1232 edid_cvt_mode(1 + x[5], t);
1233
1234 print_timings(" ", &t, "CVT", s.c_str());
1235 }
1236
1237 // tag 0x25
1238
parse_displayid_dynamic_video_timings_range_limits(const unsigned char * x)1239 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1240 {
1241 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1242
1243 if (!check_displayid_datablock_length(x, 9, 9))
1244 return;
1245
1246 printf(" Minimum Pixel Clock: %u kHz\n",
1247 1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1248 printf(" Maximum Pixel Clock: %u kHz\n",
1249 1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1250 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1251 if (x[1] & 7)
1252 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1253 else
1254 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1255 printf(" Seamless Dynamic Video Timing Support: %s\n",
1256 (x[11] & 0x80) ? "Yes" : "No");
1257 }
1258
1259 // tag 0x26
1260
1261 static const char *colorspace_eotf_combinations[] = {
1262 "sRGB",
1263 "BT.601",
1264 "BT.709/BT.1886",
1265 "Adobe RGB",
1266 "DCI-P3",
1267 "BT.2020",
1268 "BT.2020/SMPTE ST 2084"
1269 };
1270
1271 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1272
1273 static const char *colorspaces[] = {
1274 "Undefined",
1275 "sRGB",
1276 "BT.601",
1277 "BT.709",
1278 "Adobe RGB",
1279 "DCI-P3",
1280 "BT.2020",
1281 "Custom"
1282 };
1283
1284 static const char *eotfs[] = {
1285 "Undefined",
1286 "sRGB",
1287 "BT.601",
1288 "BT.1886",
1289 "Adobe RGB",
1290 "DCI-P3",
1291 "BT.2020",
1292 "Gamma function",
1293 "SMPTE ST 2084",
1294 "Hybrid Log",
1295 "Custom"
1296 };
1297
parse_displayid_interface_features(const unsigned char * x)1298 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1299 {
1300 check_displayid_datablock_revision(x[1]);
1301
1302 if (!check_displayid_datablock_length(x, 9))
1303 return;
1304
1305 dispid.has_display_interface_features = true;
1306 unsigned len = x[2];
1307 if (len > 0) print_flags(" Supported bpc for RGB encoding", x[3], bpc444);
1308 if (len > 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1309 if (len > 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1310 if (len > 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1311 if (len > 4 && x[7])
1312 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1313 74.25 * x[7]);
1314 if (len > 5) print_flags(" Supported audio capability and features (kHz)",
1315 x[8], audiorates, true);
1316 if (len > 6) print_flags(" Supported color space and EOTF standard combination 1",
1317 x[9], colorspace_eotf_combinations);
1318 if (len > 7) print_flags(" Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1319
1320 unsigned i = 0;
1321
1322 if (len > 8 && x[11]) {
1323 printf(" Supported color space and EOTF additional combinations:");
1324 for (i = 0; i < x[11]; i++) {
1325 if (i > 6) {
1326 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1327 break;
1328 } else if (i + 10 > len) {
1329 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1330 break;
1331 }
1332
1333 const char *colorspace = "Out of range";
1334 const char *eotf = "Out of range";
1335 unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1336 unsigned eotf_index = x[12 + i] & 0xf;
1337
1338 if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1339 colorspace = colorspaces[colorspace_index];
1340 if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1341 eotf = eotfs[eotf_index];
1342
1343 if (i > 0)
1344 printf(", ");
1345 if (!strcmp(colorspace, eotf))
1346 printf("%s", colorspace);
1347 else
1348 printf("%s/%s", colorspace, eotf);
1349 }
1350 printf("\n");
1351 }
1352 check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1353 }
1354
1355 // tag 0x29
1356
parse_displayid_ContainerID(const unsigned char * x)1357 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1358 {
1359 check_displayid_datablock_revision(x[1]);
1360
1361 if (check_displayid_datablock_length(x, 16, 16)) {
1362 x += 3;
1363 printf(" Container ID: %s\n", containerid2s(x).c_str());
1364 }
1365 }
1366
1367 // tag 0x32
1368
parse_displayid_type_10_timing(const unsigned char * x,bool is_cta)1369 void edid_state::parse_displayid_type_10_timing(const unsigned char *x, bool is_cta)
1370 {
1371 struct timings t = {};
1372 std::string s("aspect ");
1373
1374 t.hact = 1 + (x[1] | (x[2] << 8));
1375 t.vact = 1 + (x[3] | (x[4] << 8));
1376 calc_ratio(&t);
1377 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1378
1379 switch ((x[0] >> 5) & 0x3) {
1380 case 0:
1381 s += ", no 3D stereo";
1382 break;
1383 case 1:
1384 s += ", 3D stereo";
1385 break;
1386 case 2:
1387 s += ", 3D stereo depends on user action";
1388 break;
1389 case 3:
1390 s += ", reserved";
1391 fail("Reserved stereo 0x03.\n");
1392 break;
1393 }
1394
1395 switch (x[0] & 0x07) {
1396 case 1: t.rb = RB_CVT_V1; break;
1397 case 2: t.rb = RB_CVT_V2; break;
1398 case 3: t.rb = RB_CVT_V3; break;
1399 default: break;
1400 }
1401
1402 if (x[0] & 0x10) {
1403 if (t.rb == RB_CVT_V2) {
1404 s += ", refresh rate * (1000/1001) supported";
1405 t.rb |= RB_ALT;
1406 } else if (t.rb == RB_CVT_V3) {
1407 s += ", hblank is 160 pixels";
1408 t.rb |= RB_ALT;
1409 } else {
1410 fail("VR_HB must be 0.\n");
1411 }
1412 }
1413 if (x[0] & 0x80)
1414 s += ", YCbCr 4:2:0";
1415
1416 edid_cvt_mode(1 + x[5], t);
1417
1418 print_timings(" ", &t, "CVT", s.c_str());
1419 if (is_cta) {
1420 timings_ext te(t, "CVT", s);
1421 cta.vec_vtdbs.push_back(te);
1422 }
1423 }
1424
1425 // tag 0x7e, OUI 3A-02-92 (VESA)
1426
parse_displayid_vesa(const unsigned char * x)1427 void edid_state::parse_displayid_vesa(const unsigned char *x)
1428 {
1429 check_displayid_datablock_revision(x[1]);
1430
1431 if (!check_displayid_datablock_length(x, 5, 7))
1432 return;
1433
1434 unsigned len = x[2];
1435 x += 6;
1436 printf(" Data Structure Type: ");
1437 switch (x[0] & 0x07) {
1438 case 0x00: printf("eDP\n"); break;
1439 case 0x01: printf("DP\n"); break;
1440 default: printf("Reserved\n"); break;
1441 }
1442 printf(" Default Colorspace and EOTF Handling: %s\n",
1443 (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1444 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1445 x[1] & 0xf);
1446 printf(" Multi-SST Operation: ");
1447 switch ((x[1] >> 5) & 0x03) {
1448 case 0x00: printf("Not Supported\n"); break;
1449 case 0x01: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1450 case 0x02: printf("Four Streams (number of links shall be 4)\n"); break;
1451 case 0x03: printf("Reserved\n"); break;
1452 }
1453 if (len >= 7) {
1454 double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1455 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1456 }
1457 }
1458
1459 // tag 0x81
1460
parse_displayid_cta_data_block(const unsigned char * x)1461 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1462 {
1463 check_displayid_datablock_revision(x[1]);
1464
1465 unsigned len = x[2];
1466 unsigned i;
1467
1468 if (len > 248) {
1469 fail("Length is > 248.\n");
1470 len = 248;
1471 }
1472 x += 3;
1473
1474 for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1475 unsigned tag = (x[i] & 0xe0) << 3;
1476
1477 if (tag == 0x700)
1478 tag |= x[i + 1];
1479 bool duplicate = dispid.found_tags.find(tag) != dispid.found_tags.end();
1480
1481 cta_block(x + i, duplicate);
1482 if (!duplicate)
1483 dispid.found_tags.insert(tag);
1484 }
1485
1486 if (i != len)
1487 fail("Length is %u instead of %u.\n", len, i);
1488 }
1489
1490 // DisplayID main
1491
product_type(unsigned char x,bool heading)1492 std::string edid_state::product_type(unsigned char x, bool heading)
1493 {
1494 std::string headingstr;
1495
1496 if (dispid.version < 0x20) {
1497 headingstr = "Display Product Type";
1498 if (heading) return headingstr;
1499 dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1500 switch (x) {
1501 case 0: return "Extension Section";
1502 case 1: return "Test Structure; test equipment only";
1503 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1504 case 3: return "Standalone display device";
1505 case 4: return "Television receiver";
1506 case 5: return "Repeater/translator";
1507 case 6: return "DIRECT DRIVE monitor";
1508 default: break;
1509 }
1510 } else {
1511 headingstr = "Display Product Primary Use Case";
1512 if (heading) return headingstr;
1513 dispid.is_display = x >= 2 && x <= 8;
1514 switch (x) {
1515 case 0: return "Same primary use case as the base section";
1516 case 1: return "Test Structure; test equipment only";
1517 case 2: return "None of the listed primary use cases; generic display";
1518 case 3: return "Television (TV) display";
1519 case 4: return "Desktop productivity display";
1520 case 5: return "Desktop gaming display";
1521 case 6: return "Presentation display";
1522 case 7: return "Head-mounted Virtual Reality (VR) display";
1523 case 8: return "Head-mounted Augmented Reality (AR) display";
1524 default: break;
1525 }
1526 }
1527 fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1528 return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1529 }
1530
preparse_displayid_block(const unsigned char * x)1531 void edid_state::preparse_displayid_block(const unsigned char *x)
1532 {
1533 unsigned length = x[2];
1534
1535 if (length > 121)
1536 length = 121;
1537
1538 unsigned offset = 5;
1539
1540 dispid.preparsed_displayid_blocks++;
1541 while (length > 0) {
1542 unsigned tag = x[offset];
1543 unsigned len = x[offset + 2];
1544
1545 switch (tag) {
1546 case 0x02:
1547 dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1548 break;
1549 case 0x0e:
1550 dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1551 break;
1552 default:
1553 break;
1554 }
1555
1556 if (length < 3)
1557 break;
1558
1559 if (length < len + 3)
1560 break;
1561
1562 if (!tag && !len)
1563 break;
1564
1565 length -= len + 3;
1566 offset += len + 3;
1567 }
1568 }
1569
parse_displayid_block(const unsigned char * x)1570 void edid_state::parse_displayid_block(const unsigned char *x)
1571 {
1572 unsigned version = x[1];
1573 unsigned length = x[2];
1574 unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
1575 unsigned ext_count = x[4];
1576 unsigned i;
1577
1578 printf(" Version: %u.%u\n Extension Count: %u\n",
1579 version >> 4, version & 0xf, ext_count);
1580
1581 if (dispid.is_base_block) {
1582 dispid.version = version;
1583 printf(" %s: %s\n", product_type(prod_type, true).c_str(),
1584 product_type(prod_type, false).c_str());
1585 if (!prod_type)
1586 fail("DisplayID Base Block has no product type.\n");
1587 if (ext_count != dispid.preparsed_displayid_blocks - 1)
1588 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
1589 ext_count,
1590 ext_count > 1 ? "s" : "",
1591 dispid.preparsed_displayid_blocks - 1);
1592 } else {
1593 if (prod_type)
1594 fail("Product Type should be 0 in extension block.\n");
1595 if (ext_count)
1596 fail("Extension Count should be 0 in extension block.\n");
1597 if (version != dispid.version)
1598 fail("Got version %u.%u, expected %u.%u.\n",
1599 version >> 4, version & 0xf,
1600 dispid.version >> 4, dispid.version & 0xf);
1601 }
1602
1603 if (length > 121) {
1604 fail("DisplayID length %d is greater than 121.\n", length);
1605 length = 121;
1606 }
1607
1608 unsigned offset = 5;
1609 bool first_data_block = true;
1610 while (length > 0) {
1611 unsigned tag = x[offset];
1612 unsigned oui = 0;
1613
1614 switch (tag) {
1615 // DisplayID 1.3:
1616 case 0x00: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
1617 case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1618 case 0x02: data_block = "Color Characteristics Data Block"; break;
1619 case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1620 case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1621 case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1622 case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1623 case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1624 case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1625 case 0x09: data_block = "Video Timing Range Data Block"; break;
1626 case 0x0a: data_block = "Product Serial Number Data Block"; break;
1627 case 0x0b: data_block = "GP ASCII String Data Block"; break;
1628 case 0x0c: data_block = "Display Device Data Data Block"; break;
1629 case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1630 case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1631 case 0x0f: data_block = "Display Interface Data Block"; break;
1632 case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1633 case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1634 case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1635 case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1636 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1637 // DisplayID 2.0
1638 case 0x20: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
1639 case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1640 case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1641 case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1642 case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1643 case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1644 case 0x26: data_block = "Display Interface Features Data Block"; break;
1645 case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1646 case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1647 case 0x29: data_block = "ContainerID Data Block"; break;
1648 case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1649 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1650 case 0x7e: // DisplayID 2.0
1651 case 0x7f: // DisplayID 1.3
1652 if ((tag == 0x7e && version >= 0x20) ||
1653 (tag == 0x7f && version < 0x20)) {
1654 oui = (x[offset + 3] << 16) + (x[offset + 4] << 8) + x[offset + 5];
1655 const char *name = oui_name(oui);
1656 bool reversed = false;
1657
1658 if (!name) {
1659 name = oui_name(oui, true);
1660 if (name)
1661 reversed = true;
1662 }
1663 if (name)
1664 data_block = std::string("Vendor-Specific Data Block (") + name + ")";
1665 else
1666 data_block = "Vendor-Specific Data Block, OUI " + ouitohex(oui);
1667 if (reversed)
1668 fail((std::string("OUI ") + ouitohex(oui) + " is in the wrong byte order.\n").c_str());
1669 } else {
1670 data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")";
1671 }
1672 break;
1673 // 0x80 RESERVED
1674 case 0x81: data_block = "CTA-861 DisplayID Data Block (" + utohex(tag) + ")"; break;
1675 // 0x82 .. 0xff RESERVED
1676 default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")"; break;
1677 }
1678
1679 if (version >= 0x20 && (tag < 0x20 || tag == 0x7f))
1680 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1681 version >> 4, version & 0xf);
1682 if (version < 0x20 && tag >= 0x20 && tag <= 0x7e)
1683 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1684 version >> 4, version & 0xf);
1685
1686 if (length < 3) {
1687 // report a problem when the remaining bytes are not 0.
1688 if (tag || x[offset + 1]) {
1689 fail("Not enough bytes remain (%d) for a DisplayID data block or the DisplayID filler is non-0.\n", length);
1690 }
1691 break;
1692 }
1693
1694 unsigned block_rev = x[offset + 1] & 0x07;
1695 unsigned len = x[offset + 2];
1696
1697 if (length < len + 3) {
1698 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1699 break;
1700 }
1701
1702 if (!tag && !len) {
1703 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1704 if (!memchk(x + offset, length)) {
1705 fail("Non-0 filler bytes in the DisplayID block.\n");
1706 }
1707 break;
1708 }
1709
1710 printf(" %s:\n", data_block.c_str());
1711
1712 switch (tag) {
1713 case 0x00: parse_displayid_product_id(x + offset); break;
1714 case 0x01: parse_displayid_parameters(x + offset); break;
1715 case 0x02: parse_displayid_color_characteristics(x + offset); break;
1716 case 0x03:
1717 check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
1718 for (i = 0; i < len / 20; i++)
1719 parse_displayid_type_1_7_timing(&x[offset + 3 + (i * 20)], false, block_rev);
1720 break;
1721 case 0x04:
1722 check_displayid_datablock_revision(x[offset + 1]);
1723 for (i = 0; i < len / 11; i++)
1724 parse_displayid_type_2_timing(&x[offset + 3 + (i * 11)]);
1725 break;
1726 case 0x05:
1727 check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
1728 for (i = 0; i < len / 3; i++)
1729 parse_displayid_type_3_timing(&x[offset + 3 + (i * 3)]);
1730 break;
1731 case 0x06:
1732 check_displayid_datablock_revision(x[offset + 1], 0xc0, 1);
1733 for (i = 0; i < len; i++)
1734 parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6, x[offset + 3 + i]);
1735 break;
1736 case 0x07:
1737 check_displayid_datablock_revision(x[offset + 1]);
1738 for (i = 0; i < min(len, 10) * 8; i++)
1739 if (x[offset + 3 + i / 8] & (1 << (i % 8))) {
1740 char type[16];
1741 sprintf(type, "DMT 0x%02x", i + 1);
1742 print_timings(" ", find_dmt_id(i + 1), type);
1743 }
1744 break;
1745 case 0x08:
1746 check_displayid_datablock_revision(x[offset + 1]);
1747 for (i = 0; i < min(len, 8) * 8; i++)
1748 if (x[offset + 3 + i / 8] & (1 << (i % 8))) {
1749 char type[16];
1750 sprintf(type, "VIC %3u", i + 1);
1751 print_timings(" ", find_vic_id(i + 1), type);
1752 }
1753 break;
1754 case 0x09: parse_displayid_video_timing_range_limits(x + offset); break;
1755 case 0x0a:
1756 case 0x0b: parse_displayid_string(x + offset); break;
1757 case 0x0c: parse_displayid_display_device(x + offset); break;
1758 case 0x0d: parse_displayid_intf_power_sequencing(x + offset); break;
1759 case 0x0e: parse_displayid_transfer_characteristics(x + offset); break;
1760 case 0x0f: parse_displayid_display_intf(x + offset); break;
1761 case 0x10: parse_displayid_stereo_display_intf(x + offset); break;
1762 case 0x11:
1763 check_displayid_datablock_revision(x[offset + 1]);
1764 for (i = 0; i < len / 7; i++)
1765 parse_displayid_type_5_timing(&x[offset + 3 + (i * 7)]);
1766 break;
1767 case 0x12: parse_displayid_tiled_display_topology(x + offset, false); break;
1768 case 0x13:
1769 check_displayid_datablock_revision(x[offset + 1]);
1770 for (i = 0; i < len; i += (x[offset + 3 + i + 2] & 0x40) ? 17 : 14)
1771 parse_displayid_type_6_timing(&x[offset + 3 + i]);
1772 break;
1773 case 0x20: parse_displayid_product_id(x + offset); break;
1774 case 0x21:
1775 if (block_rev >= 1)
1776 check_displayid_datablock_revision(x[offset + 1], 0x80, 1);
1777 else
1778 check_displayid_datablock_revision(x[offset + 1], 0x80, 0);
1779 parse_displayid_parameters_v2(x + offset, block_rev);
1780 break;
1781 case 0x22: {
1782 unsigned sz = 20;
1783
1784 if (block_rev >= 2)
1785 check_displayid_datablock_revision(x[offset + 1], 0x08, 2);
1786 else if (block_rev == 1)
1787 check_displayid_datablock_revision(x[offset + 1], 0x08, 1);
1788 else
1789 check_displayid_datablock_revision(x[offset + 1]);
1790 sz += (x[offset + 1] & 0x70) >> 4;
1791 if (block_rev >= 1 && (x[offset + 1] & 0x08))
1792 printf(" These timings support DSC pass-through\n");
1793 for (i = 0; i < len / sz; i++)
1794 parse_displayid_type_1_7_timing(&x[offset + 3 + i * sz], true, block_rev);
1795 break;
1796 }
1797 case 0x23:
1798 if (block_rev)
1799 check_displayid_datablock_revision(x[offset + 1], 0xe8, 1);
1800 else
1801 check_displayid_datablock_revision(x[offset + 1], 0xc8);
1802 if (x[offset + 1] & 0x08) {
1803 for (i = 0; i < len / 2; i++)
1804 parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6,
1805 x[offset + 3 + i * 2] |
1806 (x[offset + 4 + i * 2] << 8));
1807 } else {
1808 for (i = 0; i < len; i++)
1809 parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6,
1810 x[offset + 3 + i]);
1811 }
1812 break;
1813 case 0x24:
1814 check_displayid_datablock_revision(x[offset + 1]);
1815 for (i = 0; i < len / 6; i++)
1816 parse_displayid_type_9_timing(&x[offset + 3 + i * 6]);
1817 break;
1818 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x + offset); break;
1819 case 0x26: parse_displayid_interface_features(x + offset); break;
1820 case 0x27: parse_displayid_stereo_display_intf(x + offset); break;
1821 case 0x28: parse_displayid_tiled_display_topology(x + offset, true); break;
1822 case 0x29: parse_displayid_ContainerID(x + offset); break;
1823 case 0x32: {
1824 unsigned sz = 6 + ((x[offset + 1] & 0x70) >> 4);
1825
1826 check_displayid_datablock_revision(x[offset + 1], 0x10);
1827 for (i = 0; i < len / sz; i++)
1828 parse_displayid_type_10_timing(&x[offset + 3 + i * sz]);
1829 break;
1830 }
1831 case 0x81: parse_displayid_cta_data_block(x + offset); break;
1832 case 0x7e:
1833 if (oui == 0x3a0292) {
1834 parse_displayid_vesa(x + offset);
1835 break;
1836 }
1837 // fall-through
1838 default: hex_block(" ", x + offset + 3, len); break;
1839 }
1840
1841 if ((tag == 0x00 || tag == 0x20) &&
1842 (!dispid.is_base_block || !first_data_block))
1843 fail("%s is required to be the first DisplayID Data Block.\n",
1844 data_block.c_str());
1845 length -= len + 3;
1846 offset += len + 3;
1847 first_data_block = false;
1848 }
1849
1850 /*
1851 * DisplayID length field is number of following bytes
1852 * but checksum is calculated over the entire structure
1853 * (excluding DisplayID-in-EDID magic byte)
1854 */
1855 data_block.clear();
1856 do_checksum(" ", x + 1, x[2] + 5);
1857
1858 if (!memchk(x + 1 + x[2] + 5, 0x7f - (1 + x[2] + 5))) {
1859 data_block = "Padding";
1860 fail("DisplayID padding contains non-zero bytes.\n");
1861 }
1862 dispid.is_base_block = false;
1863 }
1864
check_displayid_blocks()1865 void edid_state::check_displayid_blocks()
1866 {
1867 data_block = "DisplayID";
1868 if (!dispid.has_product_identification)
1869 fail("Missing DisplayID Product Identification Data Block.\n");
1870 if (dispid.is_display && !dispid.has_display_parameters)
1871 fail("Missing DisplayID Display Parameters Data Block.\n");
1872 if (dispid.is_display && !dispid.has_display_interface_features)
1873 fail("Missing DisplayID Display Interface Features Data Block.\n");
1874 if (dispid.is_display && !dispid.has_type_1_7)
1875 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
1876 dispid.version >= 0x20 ? "VII" : "I");
1877 if (dispid.preferred_timings.empty())
1878 fail("DisplayID expects at least one preferred timing.\n");
1879 }
1880