edid-decode: add 'silent' arg to data_block_oui()
[edid-decode.git] / parse-displayid-block.cpp
blobf4c8fc0477376bc052b6371f51009c552335197c
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 <math.h>
12 #include "edid-decode.h"
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};
18 // misc functions
20 static void print_flags(const char *label, unsigned char flag_byte,
21 const char **flags, bool reverse = false)
23 if (!flag_byte)
24 return;
26 unsigned countflags = 0;
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++;
40 printf("\n");
43 void edid_state::check_displayid_datablock_revision(unsigned char hdr,
44 unsigned char valid_flags,
45 unsigned char rev)
47 unsigned char revision = hdr & 7;
48 unsigned char flags = hdr & ~7 & ~valid_flags;
50 if (revision != rev)
51 warn("Unexpected revision (%u != %u).\n", revision, rev);
52 if (flags)
53 warn("Unexpected flags (0x%02x).\n", flags);
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)
61 unsigned char len = x[2];
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;
72 if (len > payloaddumpstart)
73 hex_block(" ", x + 3 + payloaddumpstart, len - payloaddumpstart);
74 return false;
77 // tag 0x00 and 0x20
79 void edid_state::parse_displayid_product_id(const unsigned char *x)
81 check_displayid_datablock_revision(x[1]);
83 dispid.has_product_identification = true;
84 printf(" Product Code: %u\n", x[6] | (x[7] << 8));
85 unsigned sn = x[8] | (x[9] << 8) | (x[10] << 16) | (x[11] << 24);
86 if (sn) {
87 if (hide_serial_numbers)
88 printf(" Serial Number: ...\n");
89 else
90 printf(" Serial Number: %u\n", sn);
92 unsigned week = x[12];
93 unsigned year = 2000 + x[13];
94 printf(" %s: %u",
95 week == 0xff ? "Model Year" : "Year of Manufacture", year);
96 if (week && week <= 0x36)
97 printf(", Week %u", week);
98 printf("\n");
99 if (x[14]) {
100 char buf[256];
102 memcpy(buf, x + 15, x[14]);
103 buf[x[14]] = 0;
104 printf(" Product ID: %s\n", buf);
108 // tag 0x01
110 static const char *feature_support_flags[] = {
111 "De-interlacing",
112 "Support ACP, ISRC1, or ISRC2packets",
113 "Fixed pixel format",
114 "Fixed timing",
115 "Power management (DPM)",
116 "Audio input override",
117 "Separate audio inputs provided",
118 "Audio support on video interface"
121 static void print_flag_lines(const char *indent, const char *label,
122 unsigned char flag_byte, const char **flags)
124 if (flag_byte) {
125 printf("%s\n", label);
127 for (int i = 0; i < 8; i++)
128 if (flag_byte & (1 << i))
129 printf("%s%s\n", indent, flags[i]);
133 void edid_state::set_displayid_native_res(unsigned w, unsigned h)
135 if (dispid.native_width &&
136 (dispid.native_width != w || dispid.native_height != h)) {
137 fail("Native resolution mismatch: %ux%u -> %ux%u.\n",
138 dispid.native_width, dispid.native_height, w, h);
139 return;
142 if (!w && !h)
143 return;
145 if (!w ^ !h) {
146 fail("Invalid Native Pixel Format %ux%u.\n", w, h);
147 } else {
148 dispid.native_width = w;
149 dispid.native_height = h;
153 void edid_state::parse_displayid_parameters(const unsigned char *x)
155 check_displayid_datablock_revision(x[1]);
157 if (!check_displayid_datablock_length(x, 12, 12))
158 return;
160 if (dispid.has_display_parameters)
161 fail("Duplicate Display Parameters Data Block.\n");
162 dispid.has_display_parameters = true;
163 dispid.image_width = (x[4] << 8) + x[3];
164 dispid.image_height = (x[6] << 8) + x[5];
165 if (dispid.image_width > image_width ||
166 dispid.image_height > image_height) {
167 image_width = dispid.image_width;
168 image_height = dispid.image_height;
170 printf(" Image size: %.1f mm x %.1f mm\n",
171 dispid.image_width / 10.0, dispid.image_height / 10.0);
172 unsigned w = (x[8] << 8) + x[7];
173 unsigned h = (x[10] << 8) + x[9];
174 printf(" Display native pixel format: %ux%u\n", w, h);
175 set_displayid_native_res(w, h);
176 print_flag_lines(" ", " Feature support flags:",
177 x[11], feature_support_flags);
179 if (x[12] != 0xff)
180 printf(" Gamma: %.2f\n", ((x[12] + 100.0) / 100.0));
181 printf(" Aspect ratio: %.2f\n", ((x[13] + 100.0) / 100.0));
182 printf(" Dynamic bpc native: %d\n", (x[14] & 0xf) + 1);
183 printf(" Dynamic bpc overall: %d\n", ((x[14] >> 4) & 0xf) + 1);
186 // tag 0x02
188 static const char *std_colorspace_ids[] = {
189 "sRGB",
190 "BT.601",
191 "BT.709",
192 "Adobe RGB",
193 "DCI-P3",
194 "NTSC",
195 "EBU",
196 "Adobe Wide Gamut RGB",
197 "DICOM"
200 static double fp2d(unsigned short fp)
202 return fp / 4096.0;
205 void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
207 check_displayid_datablock_revision(x[1], 0xf8, 1);
209 unsigned cie_year = (x[1] & 0x80) ? 1976 : 1931;
210 unsigned xfer_id = (x[1] >> 3) & 0x0f;
211 unsigned num_whitepoints = x[3] & 0x0f;
212 unsigned num_primaries = (x[3] >> 4) & 0x07;
213 bool temporal_color = x[3] & 0x80;
214 unsigned offset = 4;
216 printf(" Uses %s color\n", temporal_color ? "temporal" : "spatial");
217 printf(" Uses %u CIE (x, y) coordinates\n", cie_year);
218 if (xfer_id) {
219 printf(" Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id);
220 if (!(dispid.preparsed_xfer_ids & (1 << xfer_id)))
221 fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id);
223 if (!num_primaries) {
224 printf(" Uses color space %s\n",
225 x[4] >= ARRAY_SIZE(std_colorspace_ids) ? "Reserved" :
226 std_colorspace_ids[x[4]]);
227 offset++;
229 for (unsigned i = 0; i < num_primaries; i++) {
230 unsigned idx = offset + 3 * i;
232 printf(" Primary #%u: (%.4f, %.4f)\n", i,
233 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
234 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
236 offset += 3 * num_primaries;
237 for (unsigned i = 0; i < num_whitepoints; i++) {
238 unsigned idx = offset + 3 * i;
240 printf(" White point #%u: (%.4f, %.4f)\n", i,
241 fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
242 fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
246 // tag 0x03 and 0x22
248 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
249 bool type7, unsigned block_rev, bool is_cta)
251 struct timings t = {};
252 unsigned hbl, vbl;
253 std::string name = is_cta ? std::string("VTDB ") + std::to_string(cta.vec_vtdbs.size() + 1) : "DTD";
254 std::string s("aspect ");
256 dispid.has_type_1_7 = true;
257 t.pixclk_khz = (type7 ? 1 : 10) * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
258 switch (x[3] & 0xf) {
259 case 0:
260 s += "1:1";
261 t.hratio = t.vratio = 1;
262 break;
263 case 1:
264 s += "5:4";
265 t.hratio = 5;
266 t.vratio = 4;
267 break;
268 case 2:
269 s += "4:3";
270 t.hratio = 4;
271 t.vratio = 3;
272 break;
273 case 3:
274 s += "15:9";
275 t.hratio = 15;
276 t.vratio = 9;
277 break;
278 case 4:
279 s += "16:9";
280 t.hratio = 16;
281 t.vratio = 9;
282 break;
283 case 5:
284 s += "16:10";
285 t.hratio = 16;
286 t.vratio = 10;
287 break;
288 case 6:
289 s += "64:27";
290 t.hratio = 64;
291 t.vratio = 27;
292 break;
293 case 7:
294 s += "256:135";
295 t.hratio = 256;
296 t.vratio = 135;
297 break;
298 case 8:
299 s += "undefined";
300 break;
301 default:
302 s += "reserved";
303 fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
304 break;
306 switch ((x[3] >> 5) & 0x3) {
307 case 0:
308 s += ", no 3D stereo";
309 break;
310 case 1:
311 s += ", 3D stereo";
312 dispid.has_stereo = true;
313 break;
314 case 2:
315 s += ", 3D stereo depends on user action";
316 dispid.has_stereo = true;
317 break;
318 case 3:
319 s += ", reserved";
320 fail("Reserved stereo 0x03.\n");
321 break;
323 if (block_rev >= 2 && (x[3] & 0x80)) {
324 s += ", YCbCr 4:2:0";
325 dispid.has_ycbcr_420 = true;
328 t.hact = 1 + (x[4] | (x[5] << 8));
329 hbl = 1 + (x[6] | (x[7] << 8));
330 t.hfp = 1 + (x[8] | ((x[9] & 0x7f) << 8));
331 t.hsync = 1 + (x[10] | (x[11] << 8));
332 t.hbp = hbl - t.hfp - t.hsync;
333 if ((x[9] >> 7) & 0x1)
334 t.pos_pol_hsync = true;
335 t.vact = 1 + (x[12] | (x[13] << 8));
336 vbl = 1 + (x[14] | (x[15] << 8));
337 t.vfp = 1 + (x[16] | ((x[17] & 0x7f) << 8));
338 t.vsync = 1 + (x[18] | (x[19] << 8));
339 t.vbp = vbl - t.vfp - t.vsync;
340 if ((x[17] >> 7) & 0x1)
341 t.pos_pol_vsync = true;
343 if (x[3] & 0x10) {
344 t.interlaced = true;
345 t.vfp /= 2;
346 t.vsync /= 2;
347 t.vbp /= 2;
349 if (block_rev < 2 && (x[3] & 0x80)) {
350 s += ", preferred";
351 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
354 print_timings(" ", &t, name.c_str(), s.c_str(), true);
355 if (is_cta) {
356 timings_ext te(t, name.c_str(), s);
357 cta.vec_vtdbs.push_back(te);
359 // Only use a T7VTDB if is cannot be expressed by a
360 // DTD or a T10VTDB.
361 if (t.hact <= 4095 && t.vact <= 4095 &&
362 t.pixclk_khz <= 655360 && !(x[3] & 0xe0)) {
363 fail("This T7VTDB can be represented as an 18-byte DTD.\n");
364 return;
366 unsigned htot = t.hact + t.hfp + t.hsync + t.hbp;
367 unsigned vtot = t.vact + t.vfp + t.vsync + t.vbp;
368 unsigned refresh = (t.pixclk_khz * 1000ULL) / (htot * vtot);
370 for (unsigned rb = RB_NONE; rb <= RB_CVT_V3; rb++) {
371 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, rb);
372 if (match_timings(t, cvt_t)) {
373 fail("This T7VTDB can be represented as a T10VTDB.\n");
374 return;
377 timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, RB_CVT_V3,
378 false, false, true);
379 if (match_timings(t, cvt_t))
380 fail("This T7VTDB can be represented as a T10VTDB.\n");
384 // tag 0x04
386 void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
388 struct timings t = {};
389 unsigned hbl, vbl;
390 std::string s("aspect ");
392 t.pixclk_khz = 10 * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
393 t.hact = 8 + 8 * (x[4] | ((x[5] & 0x01) << 8));
394 hbl = 8 + 8 * ((x[5] & 0xfe) >> 1);
395 t.hfp = 8 + 8 * ((x[6] & 0xf0) >> 4);
396 t.hsync = 8 + 8 * (x[6] & 0xf);
397 t.hbp = hbl - t.hfp - t.hsync;
398 if ((x[3] >> 3) & 0x1)
399 t.pos_pol_hsync = true;
400 t.vact = 1 + (x[7] | ((x[8] & 0xf) << 8));
401 vbl = 1 + x[9];
402 t.vfp = 1 + (x[10] >> 4);
403 t.vsync = 1 + (x[10] & 0xf);
404 t.vbp = vbl - t.vfp - t.vsync;
405 if ((x[17] >> 2) & 0x1)
406 t.pos_pol_vsync = true;
408 if (x[3] & 0x10) {
409 t.interlaced = true;
410 t.vfp /= 2;
411 t.vsync /= 2;
412 t.vbp /= 2;
415 calc_ratio(&t);
417 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
419 switch ((x[3] >> 5) & 0x3) {
420 case 0:
421 s += ", no 3D stereo";
422 break;
423 case 1:
424 s += ", 3D stereo";
425 dispid.has_stereo = true;
426 break;
427 case 2:
428 s += ", 3D stereo depends on user action";
429 dispid.has_stereo = true;
430 break;
431 case 3:
432 s += ", reserved";
433 fail("Reserved stereo 0x03.\n");
434 break;
436 if (x[3] & 0x80) {
437 s += ", preferred";
438 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
441 print_timings(" ", &t, "DTD", s.c_str(), true);
444 // tag 0x05
446 void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
448 struct timings t = {};
449 std::string s("aspect ");
451 switch (x[0] & 0xf) {
452 case 0:
453 s += "1:1";
454 t.hratio = t.vratio = 1;
455 break;
456 case 1:
457 s += "5:4";
458 t.hratio = 5;
459 t.vratio = 4;
460 break;
461 case 2:
462 s += "4:3";
463 t.hratio = 4;
464 t.vratio = 3;
465 break;
466 case 3:
467 s += "15:9";
468 t.hratio = 15;
469 t.vratio = 9;
470 break;
471 case 4:
472 s += "16:9";
473 t.hratio = 16;
474 t.vratio = 9;
475 break;
476 case 5:
477 s += "16:10";
478 t.hratio = 16;
479 t.vratio = 10;
480 break;
481 case 6:
482 s += "64:27";
483 t.hratio = 64;
484 t.vratio = 27;
485 break;
486 case 7:
487 s += "256:135";
488 t.hratio = 256;
489 t.vratio = 135;
490 break;
491 case 8:
492 s += "undefined";
493 break;
494 default:
495 s += "reserved";
496 fail("Unknown aspect 0x%02x.\n", x[0] & 0xf);
497 break;
500 t.rb = ((x[0] & 0x70) >> 4) == 1 ? RB_CVT_V1 : RB_NONE;
501 t.hact = 8 + 8 * x[1];
502 t.vact = t.hact * t.vratio / t.hratio;
504 edid_cvt_mode(1 + (x[2] & 0x7f), t);
506 if (x[0] & 0x80) {
507 s += ", preferred";
508 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
511 print_timings(" ", &t, "CVT", s.c_str());
514 // tag 0x06 and 0x23
516 void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
518 const struct timings *t = NULL;
519 char type_name[16];
521 switch (type) {
522 case 0: t = find_dmt_id(id); sprintf(type_name, "DMT 0x%02x", id); break;
523 case 1: t = find_vic_id(id); sprintf(type_name, "VIC %3u", id); break;
524 case 2: t = find_hdmi_vic_id(id); sprintf(type_name, "HDMI VIC %u", id); break;
525 default: break;
527 if (t)
528 print_timings(" ", t, type_name);
529 if (t && is_cta && !cta.t8vtdb.is_valid()) {
530 timings_ext te(*t, type_name, "");
531 cta.t8vtdb = te;
535 // tag 0x09
537 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x)
539 check_displayid_datablock_revision(x[1]);
541 if (!check_displayid_datablock_length(x, 15, 15))
542 return;
543 printf(" Pixel Clock: %.3f-%.3f MHz\n",
544 (double)((x[3] | (x[4] << 8) | (x[5] << 16)) + 1) / 100.0,
545 (double)((x[6] | (x[7] << 8) | (x[8] << 16)) + 1) / 100.0);
546 printf(" Horizontal Frequency: %u-%u kHz\n", x[9], x[10]);
547 printf(" Minimum Horizontal Blanking: %u pixels\n", x[11] | (x[12] << 8));
548 printf(" Vertical Refresh: %u-%u Hz\n", x[13], x[14]);
549 printf(" Minimum Vertical Blanking: %u lines\n", x[15] | (x[16] << 8));
550 if (x[17] & 0x80)
551 printf(" Supports Interlaced\n");
552 if (x[17] & 0x40)
553 printf(" Supports CVT\n");
554 if (x[17] & 0x20)
555 printf(" Supports CVT Reduced Blanking\n");
556 if (x[17] & 0x10)
557 printf(" Discrete frequency display device\n");
560 // tag 0x0a and 0x0b
562 void edid_state::parse_displayid_string(const unsigned char *x)
564 check_displayid_datablock_revision(x[1]);
565 if (check_displayid_datablock_length(x))
566 printf(" Text: '%s'\n", extract_string(x + 3, x[2]));
569 // tag 0x0c
571 void edid_state::parse_displayid_display_device(const unsigned char *x)
573 check_displayid_datablock_revision(x[1]);
575 if (!check_displayid_datablock_length(x, 13, 13))
576 return;
578 printf(" Display Device Technology: ");
579 switch (x[3]) {
580 case 0x00: printf("Monochrome CRT\n"); break;
581 case 0x01: printf("Standard tricolor CRT\n"); break;
582 case 0x02: printf("Other/undefined CRT\n"); break;
583 case 0x10: printf("Passive matrix TN\n"); break;
584 case 0x11: printf("Passive matrix cholesteric LC\n"); break;
585 case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
586 case 0x13: printf("Other passive matrix LC type\n"); break;
587 case 0x14: printf("Active-matrix TN\n"); break;
588 case 0x15: printf("Active-matrix IPS (all types)\n"); break;
589 case 0x16: printf("Active-matrix VA (all types)\n"); break;
590 case 0x17: printf("Active-matrix OCB\n"); break;
591 case 0x18: printf("Active-matrix ferroelectric\n"); break;
592 case 0x1f: printf("Other LC type\n"); break;
593 case 0x20: printf("DC plasma\n"); break;
594 case 0x21: printf("AC plasma\n"); break;
596 switch (x[3] & 0xf0) {
597 case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
598 case 0x40: printf("Inorganic LED\n"); break;
599 case 0x50: printf("Organic LED/OEL\n"); break;
600 case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
601 case 0x70: printf("Electrophoretic\n"); break;
602 case 0x80: printf("Electrochromic\n"); break;
603 case 0x90: printf("Electromechanical\n"); break;
604 case 0xa0: printf("Electrowetting\n"); break;
605 case 0xf0: printf("Other type not defined here\n"); break;
607 printf(" Display operating mode: ");
608 switch (x[4] >> 4) {
609 case 0x00: printf("Direct-view reflective, ambient light\n"); break;
610 case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
611 case 0x02: printf("Direct-view reflective, uses light source\n"); break;
612 case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
613 case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
614 case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
615 case 0x06: printf("Direct-view emissive\n"); break;
616 case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
617 case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
618 case 0x09: printf("Transparent display, ambient light\n"); break;
619 case 0x0a: printf("Transparent emissive display\n"); break;
620 case 0x0b: printf("Projection device using reflective light modulator\n"); break;
621 case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
622 case 0x0d: printf("Projection device using emissive image transducer\n"); break;
623 default: printf("Reserved\n"); break;
625 if (x[4] & 0x08)
626 printf(" The backlight may be switched on and off\n");
627 if (x[4] & 0x04)
628 printf(" The backlight's intensity can be controlled\n");
629 unsigned w = x[5] | (x[6] << 8);
630 unsigned h = x[7] | (x[8] << 8);
632 if (w) w++;
633 if (h) h++;
635 printf(" Display native pixel format: %ux%u\n", w, h);
636 set_displayid_native_res(w, h);
637 printf(" Aspect ratio and orientation:\n");
638 printf(" Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
639 unsigned char v = x[0x0a];
640 printf(" Default Orientation: ");
641 switch ((v & 0xc0) >> 6) {
642 case 0x00: printf("Landscape\n"); break;
643 case 0x01: printf("Portrait\n"); break;
644 case 0x02: printf("Not Fixed\n"); break;
645 case 0x03: printf("Undefined\n"); break;
647 printf(" Rotation Capability: ");
648 switch ((v & 0x30) >> 4) {
649 case 0x00: printf("None\n"); break;
650 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
651 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
652 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
654 printf(" Zero Pixel Location: ");
655 switch ((v & 0x0c) >> 2) {
656 case 0x00: printf("Upper Left\n"); break;
657 case 0x01: printf("Upper Right\n"); break;
658 case 0x02: printf("Lower Left\n"); break;
659 case 0x03: printf("Lower Right\n"); break;
661 printf(" Scan Direction: ");
662 switch (v & 0x03) {
663 case 0x00: printf("Not defined\n"); break;
664 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
665 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
666 case 0x03: printf("Reserved\n");
667 fail("Scan Direction used the reserved value 0x03.\n");
668 break;
670 printf(" Sub-pixel layout/configuration/shape: ");
671 switch (x[0x0b]) {
672 case 0x00: printf("Not defined\n"); break;
673 case 0x01: printf("RGB vertical stripes\n"); break;
674 case 0x02: printf("RGB horizontal stripes\n"); break;
675 case 0x03: printf("Vertical stripes using primary order\n"); break;
676 case 0x04: printf("Horizontal stripes using primary order\n"); break;
677 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
678 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
679 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
680 case 0x08: printf("Mosaic\n"); break;
681 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
682 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
683 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
684 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
685 default: printf("Reserved\n"); break;
687 printf(" Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
688 (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
689 printf(" Color bit depth: %u\n", x[0x0e] & 0x0f);
690 v = x[0x0f];
691 printf(" Response time for %s transition: %u ms\n",
692 (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f);
695 // tag 0x0d
697 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x)
699 check_displayid_datablock_revision(x[1]);
701 if (!check_displayid_datablock_length(x, 6, 6))
702 return;
704 printf(" Power Sequence T1 Range: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2);
705 printf(" Power Sequence T2 Range: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2);
706 printf(" Power Sequence T3 Range: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2);
707 printf(" Power Sequence T4 Min: %u.0 ms\n", (x[6] & 0x7f) * 10);
708 printf(" Power Sequence T5 Min: %u.0 ms\n", (x[7] & 0x3f) * 10);
709 printf(" Power Sequence T6 Min: %u.0 ms\n", (x[8] & 0x3f) * 10);
712 // tag 0x0e
714 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x)
716 check_displayid_datablock_revision(x[1], 0xf0, 1);
718 unsigned xfer_id = x[1] >> 4;
719 bool first_is_white = x[3] & 0x80;
720 bool four_param = x[3] & 0x20;
722 if (xfer_id) {
723 printf(" Transfer Characteristics Data Block Identifier: %u\n", xfer_id);
724 if (!(dispid.preparsed_color_ids & (1 << xfer_id)))
725 fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id);
727 if (first_is_white)
728 printf(" The first curve is the 'white' transfer characteristic\n");
729 if (x[3] & 0x40)
730 printf(" Individual response curves\n");
732 unsigned offset = 4;
733 unsigned len = x[2] - 1;
735 for (unsigned i = 0; len; i++) {
736 if ((x[3] & 0x80) && !i)
737 printf(" White curve: ");
738 else
739 printf(" Response curve #%u:",
740 i - first_is_white);
741 unsigned samples = x[offset];
742 if (four_param) {
743 if (samples != 5)
744 fail("Expected 5 samples.\n");
745 printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
746 x[offset + 1], x[offset + 2], x[offset + 3], x[offset + 4],
747 (double)(x[offset + 5] + 100.0) / 100.0);
748 samples++;
749 } else {
750 double sum = 0;
752 // The spec is not very clear about the number of samples:
753 // should this be interpreted as the actual number of
754 // samples stored in this Data Block, or as the number of
755 // samples in the curve, but where the last sample is not
756 // actually stored since it is always 0x3ff.
758 // The ATP Manager interprets this as the latter, so that's
759 // what we implement here.
760 for (unsigned j = offset + 1; j < offset + samples; j++) {
761 sum += x[j];
762 printf(" %.2f", sum * 100.0 / 1023.0);
764 printf(" 100.00\n");
766 offset += samples;
767 len -= samples;
771 // tag 0x0f
773 void edid_state::parse_displayid_display_intf(const unsigned char *x)
775 check_displayid_datablock_revision(x[1]);
777 if (!check_displayid_datablock_length(x, 10, 10))
778 return;
780 dispid.has_display_interface_features = true;
781 printf(" Interface Type: ");
782 switch (x[3] >> 4) {
783 case 0x00:
784 switch (x[3] & 0xf) {
785 case 0x00: printf("Analog 15HD/VGA\n"); break;
786 case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
787 case 0x02: printf("Analog VESA NAVI-D\n"); break;
788 default: printf("Reserved\n"); break;
790 break;
791 case 0x01: printf("LVDS\n"); break;
792 case 0x02: printf("TMDS\n"); break;
793 case 0x03: printf("RSDS\n"); break;
794 case 0x04: printf("DVI-D\n"); break;
795 case 0x05: printf("DVI-I, analog\n"); break;
796 case 0x06: printf("DVI-I, digital\n"); break;
797 case 0x07: printf("HDMI-A\n"); break;
798 case 0x08: printf("HDMI-B\n"); break;
799 case 0x09: printf("MDDI\n"); break;
800 case 0x0a: printf("DisplayPort\n"); break;
801 case 0x0b: printf("Proprietary Digital Interface\n"); break;
802 default: printf("Reserved\n"); break;
804 if (x[3] >> 4)
805 printf(" Number of Links: %u\n", x[3] & 0xf);
806 printf(" Interface Standard Version: %u.%u\n",
807 x[4] >> 4, x[4] & 0xf);
808 print_flags(" Supported bpc for RGB encoding", x[5], bpc444);
809 print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444);
810 print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx);
811 printf(" Supported Content Protection: ");
812 switch (x[8] & 0xf) {
813 case 0x00: printf("None\n"); break;
814 case 0x01: printf("HDCP "); break;
815 case 0x02: printf("DTCP "); break;
816 case 0x03: printf("DPCP "); break;
817 default: printf("Reserved "); break;
819 if (x[8] & 0xf)
820 printf("%u.%u\n", x[9] >> 4, x[9] & 0xf);
821 unsigned char v = x[0x0a] & 0xf;
822 printf(" Spread Spectrum: ");
823 switch (x[0x0a] >> 6) {
824 case 0x00: printf("None\n"); break;
825 case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break;
826 case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break;
827 case 0x03: printf("Reserved\n"); break;
829 switch (x[3] >> 4) {
830 case 0x01:
831 printf(" LVDS Color Mapping: %s mode\n",
832 (x[0x0b] & 0x10) ? "6 bit compatible" : "normal");
833 if (x[0x0b] & 0x08) printf(" LVDS supports 2.8V\n");
834 if (x[0x0b] & 0x04) printf(" LVDS supports 12V\n");
835 if (x[0x0b] & 0x02) printf(" LVDS supports 5V\n");
836 if (x[0x0b] & 0x01) printf(" LVDS supports 3.3V\n");
837 printf(" LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE");
838 if (x[0x0c] & 0x04)
839 printf(" LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High");
840 else
841 printf(" LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High");
842 printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling");
843 break;
844 case 0x0b:
845 printf(" PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE");
846 if (x[0x0b] & 0x04)
847 printf(" PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High");
848 else
849 printf(" PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High");
850 printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling");
851 break;
855 // tag 0x10 and 0x27
857 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x)
859 dispid.has_stereo_display_interface = true;
861 check_displayid_datablock_revision(x[1], 0xc0, 1);
863 switch (x[1] >> 6) {
864 case 0x00: printf(" Timings that explicitly report 3D capability\n"); break;
865 case 0x01: printf(" Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
866 case 0x02: printf(" All listed timings\n"); break;
867 case 0x03: printf(" Only Timings Codes listed here\n"); break;
870 unsigned len = x[2];
872 switch (x[4]) {
873 case 0x00:
874 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
875 (x[5] & 1) ? "0/1" : "1/0");
876 break;
877 case 0x01:
878 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
879 (x[5] & 1) ? "Right" : "Left");
880 break;
881 case 0x02:
882 printf(" Pixel Interleaved Stereo:\n");
883 for (unsigned y = 0; y < 8; y++) {
884 unsigned char v = x[5 + y];
886 printf(" ");
887 for (int x = 7; x >= 0; x--)
888 printf("%c", (v & (1 << x)) ? 'L' : 'R');
889 printf("\n");
891 break;
892 case 0x03:
893 printf(" Dual Interface, Left and Right Separate\n");
894 printf(" Carries the %s-eye view\n",
895 (x[5] & 1) ? "Right" : "Left");
896 printf(" ");
897 switch ((x[5] >> 1) & 3) {
898 case 0x00: printf("No mirroring\n"); break;
899 case 0x01: printf("Left/Right mirroring\n"); break;
900 case 0x02: printf("Top/Bottom mirroring\n"); break;
901 case 0x03: printf("Reserved\n"); break;
903 break;
904 case 0x04:
905 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
906 x[5], x[6]);
907 break;
908 case 0x05:
909 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
910 (x[5] & 1) ? "Right" : "Left");
911 break;
912 case 0xff:
913 printf(" Proprietary\n");
914 break;
915 default:
916 printf(" Reserved\n");
917 break;
919 if (!(x[1] & 0x40)) // Has No Timing Codes
920 return;
921 len -= 1 + x[3];
922 x += 4 + x[3];
923 while (1U + (x[0] & 0x1f) <= len) {
924 unsigned num_codes = x[0] & 0x1f;
925 unsigned type = x[0] >> 6;
926 char type_name[16];
928 for (unsigned i = 1; i <= num_codes; i++) {
929 switch (type) {
930 case 0x00:
931 sprintf(type_name, "DMT 0x%02x", x[i]);
932 print_timings(" ", find_dmt_id(x[i]), type_name);
933 break;
934 case 0x01:
935 sprintf(type_name, "VIC %3u", x[i]);
936 print_timings(" ", find_vic_id(x[i]), type_name);
937 break;
938 case 0x02:
939 sprintf(type_name, "HDMI VIC %u", x[i]);
940 print_timings(" ", find_hdmi_vic_id(x[i]), type_name);
941 break;
945 len -= 1 + num_codes;
946 x += 1 + num_codes;
950 // tag 0x11
952 void edid_state::parse_displayid_type_5_timing(const unsigned char *x)
954 struct timings t = {};
955 std::string s("aspect ");
957 t.hact = 1 + (x[2] | (x[3] << 8));
958 t.vact = 1 + (x[4] | (x[5] << 8));
959 calc_ratio(&t);
960 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
961 switch ((x[0] >> 5) & 0x3) {
962 case 0:
963 s += ", no 3D stereo";
964 break;
965 case 1:
966 s += ", 3D stereo";
967 dispid.has_stereo = true;
968 break;
969 case 2:
970 s += ", 3D stereo depends on user action";
971 dispid.has_stereo = true;
972 break;
973 case 3:
974 s += ", reserved";
975 fail("Reserved stereo 0x03.\n");
976 break;
978 if (x[0] & 0x10)
979 s += ", refresh rate * (1000/1001) supported";
981 t.rb = RB_CVT_V2;
982 if ((x[0] & 0x03) == 1)
983 warn("Unexpected use of 'custom reduced blanking'.\n");
984 else if ((x[0] & 0x03) > 1)
985 fail("Invalid Timing Formula.\n");
987 edid_cvt_mode(1 + x[6], t);
989 if (x[0] & 0x80) {
990 s += ", preferred";
991 dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
994 print_timings(" ", &t, "CVT", s.c_str());
997 // tag 0x12 and 0x28
999 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2)
1001 check_displayid_datablock_revision(x[1]);
1003 if (!check_displayid_datablock_length(x, 22, 22))
1004 return;
1006 dispid.has_tiled_display_topology = true;
1008 unsigned caps = x[3];
1009 unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30);
1010 unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30);
1011 unsigned tile_v_location = (x[5] & 0xf) | ((x[6] & 0x3) << 4);
1012 unsigned tile_h_location = (x[5] >> 4) | (((x[6] >> 2) & 0x3) << 4);
1013 unsigned tile_width = x[7] | (x[8] << 8);
1014 unsigned tile_height = x[9] | (x[10] << 8);
1015 unsigned pix_mult = x[11];
1017 printf(" Capabilities:\n");
1018 printf(" Behavior if it is the only tile: ");
1019 switch (caps & 0x07) {
1020 case 0x00: printf("Undefined\n"); break;
1021 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
1022 case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
1023 case 0x03: printf("Image is cloned to all other tiles\n"); break;
1024 default: printf("Reserved\n"); break;
1026 printf(" Behavior if more than one tile and fewer than total number of tiles: ");
1027 switch ((caps >> 3) & 0x03) {
1028 case 0x00: printf("Undefined\n"); break;
1029 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
1030 default: printf("Reserved\n"); break;
1032 if (caps & 0x80)
1033 printf(" Tiled display consists of a single physical display enclosure\n");
1034 else
1035 printf(" Tiled display consists of multiple physical display enclosures\n");
1036 printf(" Num horizontal tiles: %u Num vertical tiles: %u\n",
1037 num_h_tile + 1, num_v_tile + 1);
1038 printf(" Tile location: %u, %u\n", tile_h_location, tile_v_location);
1039 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1040 if (caps & 0x40) {
1041 if (pix_mult) {
1042 printf(" Top bezel size: %.1f pixels\n",
1043 pix_mult * x[12] / 10.0);
1044 printf(" Bottom bezel size: %.1f pixels\n",
1045 pix_mult * x[13] / 10.0);
1046 printf(" Right bezel size: %.1f pixels\n",
1047 pix_mult * x[14] / 10.0);
1048 printf(" Left bezel size: %.1f pixels\n",
1049 pix_mult * x[15] / 10.0);
1050 } else {
1051 fail("Bezel information bit is set, but the pixel multiplier is zero.\n");
1053 printf(" Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1054 } else if (pix_mult) {
1055 fail("No bezel information, but the pixel multiplier is non-zero.\n");
1057 if (is_v2)
1058 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1059 x[0x10], x[0x11], x[0x12]);
1060 else
1061 printf(" Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1062 x[0x10], x[0x11], x[0x12]);
1063 printf(" Tiled Display Product ID Code: %u\n",
1064 x[0x13] | (x[0x14] << 8));
1065 unsigned int sn = x[0x15] | (x[0x16] << 8) | (x[0x17] << 16)| (x[0x18] << 24);
1066 if (sn) {
1067 if (hide_serial_numbers)
1068 printf(" Tiled Display Serial Number: ...\n");
1069 else
1070 printf(" Tiled Display Serial Number: %u\n", sn);
1071 } else {
1072 fail("Tiled Display Serial Number must be non-zero.\n");
1076 // tag 0x13
1078 void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
1080 struct timings t = {};
1081 std::string s("aspect ");
1083 t.pixclk_khz = 1 + (x[0] + (x[1] << 8) + ((x[2] & 0x3f) << 16));
1084 t.hact = 1 + (x[3] | ((x[4] & 0x3f) << 8));
1085 if ((x[4] >> 7) & 0x1)
1086 t.pos_pol_hsync = true;
1087 unsigned hbl = 1 + (x[7] | ((x[9] & 0xf) << 8));
1088 t.hfp = 1 + (x[8] | ((x[9] & 0xf0) << 4));
1089 t.hsync = 1 + x[10];
1090 t.hbp = hbl - t.hfp - t.hsync;
1091 t.vact = 1 + (x[5] | ((x[6] & 0x3f) << 8));
1092 if ((x[6] >> 7) & 0x1)
1093 t.pos_pol_vsync = true;
1094 unsigned vbl = 1 + x[11];
1095 t.vfp = 1 + x[12];
1096 t.vsync = 1 + (x[13] & 0x0f);
1097 t.vbp = vbl - t.vfp - t.vsync;
1099 if (x[13] & 0x80) {
1100 t.interlaced = true;
1101 t.vfp /= 2;
1102 t.vsync /= 2;
1103 t.vbp /= 2;
1105 calc_ratio(&t);
1106 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1107 if (x[2] & 0x40) {
1108 double aspect_mult = x[14] * 3.0 / 256.0;
1109 unsigned size_mult = 1 + (x[16] >> 4);
1111 t.vsize_mm = size_mult * (1 + (x[15] | ((x[16] & 0xf) << 8)));
1112 t.hsize_mm = t.vsize_mm * aspect_mult;
1115 switch ((x[13] >> 5) & 0x3) {
1116 case 0:
1117 s += ", no 3D stereo";
1118 break;
1119 case 1:
1120 s += ", 3D stereo";
1121 dispid.has_stereo = true;
1122 break;
1123 case 2:
1124 s += ", 3D stereo depends on user action";
1125 dispid.has_stereo = true;
1126 break;
1127 case 3:
1128 s += ", reserved";
1129 fail("Reserved stereo 0x03.\n");
1130 break;
1133 if (x[2] & 0x80) {
1134 s += ", preferred";
1135 dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
1138 print_timings(" ", &t, "DTD", s.c_str(), true);
1141 static std::string ieee7542d(unsigned short fp)
1143 int exp = ((fp & 0x7c00) >> 10) - 15;
1144 unsigned fract = (fp & 0x3ff) | 0x400;
1146 if (fp == 0x8000)
1147 return "do not use";
1148 if (fp & 0x8000)
1149 return "reserved";
1150 return std::to_string(pow(2, exp) * fract / 1024.0) + " cd/m^2";
1153 // tag 0x21
1155 void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
1156 unsigned block_rev)
1158 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1159 if (!check_displayid_datablock_length(x, 29, 29))
1160 return;
1161 if (dispid.has_display_parameters)
1162 fail("Duplicate Display Parameters Data Block.\n");
1163 dispid.has_display_parameters = true;
1165 unsigned hor_size = (x[4] << 8) + x[3];
1166 unsigned vert_size = (x[6] << 8) + x[5];
1168 dispid.image_width = hor_size;
1169 dispid.image_height = vert_size;
1170 if (x[1] & 0x80) {
1171 printf(" Image size: %u mm x %u mm\n", hor_size, vert_size);
1172 dispid.image_width *= 10;
1173 dispid.image_height *= 10;
1174 } else {
1175 printf(" Image size: %.1f mm x %.1f mm\n",
1176 hor_size / 10.0, vert_size / 10.0);
1178 if (dispid.image_width > image_width ||
1179 dispid.image_height > image_height) {
1180 image_width = dispid.image_width;
1181 image_height = dispid.image_height;
1184 unsigned w = (x[8] << 8) + x[7];
1185 unsigned h = (x[10] << 8) + x[9];
1187 printf(" Display native pixel format: %ux%u\n", w, h);
1188 set_displayid_native_res(w, h);
1190 unsigned char v = x[11];
1191 printf(" Scan Orientation: ");
1192 switch (v & 0x07) {
1193 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1194 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1195 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1196 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1197 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1198 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1199 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1200 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1202 printf(" Luminance Information: ");
1203 switch ((v >> 3) & 0x03) {
1204 case 0x00: printf("Minimum guaranteed value\n"); break;
1205 case 0x01: printf("Guidance for the Source device\n"); break;
1206 default: printf("Reserved\n"); break;
1208 printf(" Color Information: CIE %u\n",
1209 (v & 0x40) ? 1976 : 1931);
1210 printf(" Audio Speaker Information: %sintegrated\n",
1211 (v & 0x80) ? "not " : "");
1212 printf(" Native Color Chromaticity:\n");
1213 printf(" Primary #1: (%.6f, %.6f)\n",
1214 fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1215 fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1216 printf(" Primary #2: (%.6f, %.6f)\n",
1217 fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1218 fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1219 printf(" Primary #3: (%.6f, %.6f)\n",
1220 fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1221 fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1222 printf(" White Point: (%.6f, %.6f)\n",
1223 fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1224 fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1225 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1226 ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1227 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1228 ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1229 printf(" Native Minimum Luminance: %s\n",
1230 ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1231 printf(" Native Color Depth: ");
1232 if (!(x[0x1e] & 0x07))
1233 printf("Not defined\n");
1234 else if (bpc444[x[0x1e] & 0x07])
1235 printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1236 else
1237 printf("Reserved\n");
1238 printf(" Display Device Technology: ");
1239 switch ((x[0x1e] >> 4) & 0x07) {
1240 case 0x00: printf("Not Specified\n"); break;
1241 case 0x01: printf("Active Matrix LCD\n"); break;
1242 case 0x02: printf("Organic LED\n"); break;
1243 default: printf("Reserved\n"); break;
1245 if (block_rev)
1246 printf(" Display Device Theme Preference: %s\n",
1247 (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1248 if (x[0x1f] != 0xff)
1249 printf(" Native Gamma EOTF: %.2f\n",
1250 (100 + x[0x1f]) / 100.0);
1253 // tag 0x24
1255 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1257 struct timings t = {};
1258 std::string s("aspect ");
1260 t.hact = 1 + (x[1] | (x[2] << 8));
1261 t.vact = 1 + (x[3] | (x[4] << 8));
1262 calc_ratio(&t);
1263 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1264 switch ((x[0] >> 5) & 0x3) {
1265 case 0:
1266 s += ", no 3D stereo";
1267 break;
1268 case 1:
1269 s += ", 3D stereo";
1270 dispid.has_stereo = true;
1271 break;
1272 case 2:
1273 s += ", 3D stereo depends on user action";
1274 dispid.has_stereo = true;
1275 break;
1276 case 3:
1277 s += ", reserved";
1278 fail("Reserved stereo 0x03.\n");
1279 break;
1281 if (x[0] & 0x10)
1282 s += ", refresh rate * (1000/1001) supported";
1284 switch (x[0] & 0x07) {
1285 case 1: t.rb = RB_CVT_V1; break;
1286 case 2: t.rb = RB_CVT_V2; break;
1287 default: break;
1290 edid_cvt_mode(1 + x[5], t);
1292 print_timings(" ", &t, "CVT", s.c_str());
1295 // tag 0x25
1297 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1299 check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1301 if (!check_displayid_datablock_length(x, 9, 9))
1302 return;
1304 printf(" Minimum Pixel Clock: %u kHz\n",
1305 1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1306 printf(" Maximum Pixel Clock: %u kHz\n",
1307 1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1308 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1309 if (x[1] & 7)
1310 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1311 else
1312 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1313 printf(" Seamless Dynamic Video Timing Support: %s\n",
1314 (x[11] & 0x80) ? "Yes" : "No");
1317 // tag 0x26
1319 static const char *colorspace_eotf_combinations[] = {
1320 "sRGB",
1321 "BT.601",
1322 "BT.709/BT.1886",
1323 "Adobe RGB",
1324 "DCI-P3",
1325 "BT.2020",
1326 "BT.2020/SMPTE ST 2084"
1329 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1331 static const char *colorspaces[] = {
1332 "Undefined",
1333 "sRGB",
1334 "BT.601",
1335 "BT.709",
1336 "Adobe RGB",
1337 "DCI-P3",
1338 "BT.2020",
1339 "Custom"
1342 static const char *eotfs[] = {
1343 "Undefined",
1344 "sRGB",
1345 "BT.601",
1346 "BT.1886",
1347 "Adobe RGB",
1348 "DCI-P3",
1349 "BT.2020",
1350 "Gamma function",
1351 "SMPTE ST 2084",
1352 "Hybrid Log",
1353 "Custom"
1356 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1358 check_displayid_datablock_revision(x[1]);
1360 if (!check_displayid_datablock_length(x, 9))
1361 return;
1363 dispid.has_display_interface_features = true;
1364 unsigned len = x[2];
1365 if (len > 0) print_flags(" Supported bpc for RGB encoding", x[3], bpc444);
1366 if (len > 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1367 if (len > 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1368 if (len > 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1369 if (len > 4 && x[7])
1370 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1371 74.25 * x[7]);
1372 if (len > 5) print_flags(" Supported audio capability and features (kHz)",
1373 x[8], audiorates, true);
1374 if (len > 6) print_flags(" Supported color space and EOTF standard combination 1",
1375 x[9], colorspace_eotf_combinations);
1376 if (len > 7) print_flags(" Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1378 unsigned i = 0;
1380 if (len > 8 && x[11]) {
1381 printf(" Supported color space and EOTF additional combinations:");
1382 for (i = 0; i < x[11]; i++) {
1383 if (i > 6) {
1384 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1385 break;
1386 } else if (i + 10 > len) {
1387 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1388 break;
1391 const char *colorspace = "Out of range";
1392 const char *eotf = "Out of range";
1393 unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1394 unsigned eotf_index = x[12 + i] & 0xf;
1396 if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1397 colorspace = colorspaces[colorspace_index];
1398 if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1399 eotf = eotfs[eotf_index];
1401 if (i > 0)
1402 printf(", ");
1403 if (!strcmp(colorspace, eotf))
1404 printf("%s", colorspace);
1405 else
1406 printf("%s/%s", colorspace, eotf);
1408 printf("\n");
1410 check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1413 // tag 0x29
1415 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1417 check_displayid_datablock_revision(x[1]);
1419 if (check_displayid_datablock_length(x, 16, 16)) {
1420 x += 3;
1421 printf(" Container ID: %s\n", containerid2s(x).c_str());
1425 // tag 0x2b
1427 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x)
1429 check_displayid_datablock_revision(x[1], 0x70);
1431 unsigned size = 6 + ((x[1] >> 4) & 0x7);
1432 unsigned len = x[2];
1433 unsigned descriptor = 1;
1435 x += 3;
1436 if (len % size)
1437 fail("DisplayID payload length %u is not a multiple of %u.\n", len, size);
1438 while (len >= size) {
1439 printf(" Descriptor #%u:\n", descriptor++);
1441 printf(" %sNative Panel Range\n", (x[0] & 1) ? "" : "Non-");
1442 unsigned v = (x[0] >> 2) & 3;
1443 switch (v) {
1444 case 0: printf(" Fixed Average V-Total\n"); break;
1445 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1446 default:
1447 printf(" Reserved %u\n", v);
1448 fail("Use of reserved value %u.\n", v);
1449 break;
1451 if (!(x[0] & 0x10))
1452 printf(" Supports Seamless Transition\n");
1453 if (x[0] & 0x02)
1454 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1455 if (x[0] & 0x20)
1456 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1457 printf(" Max Duration Increase: %.2f ms\n", x[1] / 4.0);
1458 printf(" Max Duration Decrease: %.2f ms\n", x[5] / 4.0);
1459 printf(" Min Refresh Rate: %u Hz\n", x[2]);
1460 printf(" Max Refresh Rate: %u Hz\n", 1 + x[3] + (x[4] & 3) * 256);
1462 len -= size;
1463 x += size;
1467 // tag 0x2c
1469 void edid_state::parse_displayid_arvr_hmd(const unsigned char *x)
1471 dispid.has_arvr_hdm = true;
1473 if (!native_dispid && dispid.is_arvr)
1474 fail("Not allowed for DisplayID Extension Blocks.\n");
1476 check_displayid_datablock_revision(x[1], 1);
1478 if (!check_displayid_datablock_length(x, 79, 79))
1479 return;
1481 // TODO: parse the DB
1484 // tag 0x2d
1486 void edid_state::parse_displayid_arvr_layer(const unsigned char *x)
1488 dispid.has_arvr_layer = true;
1490 if (!native_dispid && dispid.is_arvr)
1491 fail("Not allowed for DisplayID Extension Blocks.\n");
1493 check_displayid_datablock_revision(x[1], 1);
1495 if (!check_displayid_datablock_length(x, 20, 20))
1496 return;
1498 // TODO: parse the DB
1501 // tag 0x2e
1503 void edid_state::parse_displayid_brightness_lum_range(const unsigned char *x)
1505 check_displayid_datablock_revision(x[1]);
1507 if (!check_displayid_datablock_length(x, 6, 6))
1508 return;
1510 printf(" Minimum SDR Luminance (Full Coverage): %s\n",
1511 ieee7542d(x[3] | (x[4] << 8)).c_str());
1512 // TODO: test that this is > Native Minimum Luminance from Display Params DB
1513 printf(" Maximum Suggested SDR Luminance (Full Coverage): %s\n",
1514 ieee7542d(x[5] | (x[6] << 8)).c_str());
1515 // TODO: test that this is > Native Minimum Luminance from Display Params DB
1516 // and <= Native Maximum Luminance (Full Coverage) in same DB.
1517 printf(" Maximum Boost SDR Luminance: %s\n",
1518 ieee7542d(x[5] | (x[6] << 8)).c_str());
1519 // TODO: test that this is >= the previous value
1522 // tag 0x32
1524 void edid_state::parse_displayid_type_10_timing(const unsigned char *x,
1525 unsigned sz, bool is_cta)
1527 struct timings t = {};
1528 std::string name = is_cta ? std::string("VTDB ") + std::to_string(cta.vec_vtdbs.size() + 1) : "CVT";
1529 std::string s("aspect ");
1531 t.hact = 1 + (x[1] | (x[2] << 8));
1532 t.vact = 1 + (x[3] | (x[4] << 8));
1533 calc_ratio(&t);
1534 s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1536 switch ((x[0] >> 5) & 0x3) {
1537 case 0:
1538 s += ", no 3D stereo";
1539 break;
1540 case 1:
1541 s += ", 3D stereo";
1542 dispid.has_stereo = true;
1543 break;
1544 case 2:
1545 s += ", 3D stereo depends on user action";
1546 dispid.has_stereo = true;
1547 break;
1548 case 3:
1549 s += ", reserved";
1550 fail("Reserved stereo 0x03.\n");
1551 break;
1554 switch (x[0] & 0x07) {
1555 case 1: t.rb = RB_CVT_V1; break;
1556 case 2: t.rb = RB_CVT_V2; break;
1557 case 3: t.rb = RB_CVT_V3; break;
1558 default: break;
1561 unsigned rb = t.rb;
1562 unsigned rb_h_blank = rb == RB_CVT_V3 ? 80 : 0;
1563 bool alt_min_vblank = sz >= 8 ? (x[7] & 1) : 0;
1564 unsigned rb_v_min_blank = alt_min_vblank ? 300 : 460;
1565 unsigned rb_v_blank = rb_v_min_blank;
1566 bool early_vsync_rqd = false;
1568 if (x[0] & 0x10) {
1569 if (rb == RB_CVT_V2) {
1570 s += ", refresh rate * (1000/1001) supported";
1571 t.rb |= RB_ALT;
1572 } else if (rb == RB_CVT_V3) {
1573 s += ", hblank is 160 pixels";
1574 t.rb |= RB_ALT;
1575 rb_h_blank = 160;
1576 } else {
1577 fail("VR_HB must be 0.\n");
1580 if (x[0] & 0x80) {
1581 s += ", YCbCr 4:2:0";
1582 dispid.has_ycbcr_420 = true;
1585 if (x[0] & 0x08) {
1586 if (rb == RB_CVT_V3) {
1587 early_vsync_rqd = true;
1588 s += ", early-vsync";
1589 } else {
1590 fail("EVS must be 0.\n");
1594 unsigned refresh = 1 + x[5] + (sz == 6 ? 0 : ((x[6] & 3) << 8));
1596 if (sz > 6) {
1597 if (rb == RB_CVT_V3) {
1598 unsigned delta_hblank = (x[6] >> 2) & 7;
1600 if (rb_h_blank == 80)
1601 rb_h_blank = 80 + 8 * delta_hblank;
1602 else if (delta_hblank <= 5)
1603 rb_h_blank = 160 + 8 * delta_hblank;
1604 else
1605 rb_h_blank = 160 - (delta_hblank - 5) * 8;
1606 if (delta_hblank)
1607 s += ", delta-hblank=" + std::to_string(delta_hblank);
1609 rb_v_blank += ((x[6] >> 5) & 7) * (alt_min_vblank ? 20 : 35);
1610 if (rb_v_blank > rb_v_min_blank)
1611 s += ", add-vblank=" + std::to_string(rb_v_blank - rb_v_min_blank);
1612 } else {
1613 if (x[6] & 0xe0)
1614 fail("Additional_Vertical_Blank_Time must be 0.\n");
1615 if (x[6] & 0x1c)
1616 fail("Delta_Horizontal_Blank must be 0.\n");
1620 edid_cvt_mode(refresh, t, rb_h_blank, rb_v_blank, early_vsync_rqd);
1622 print_timings(" ", &t, name.c_str(), s.c_str());
1623 if (is_cta) {
1624 timings_ext te(t, name.c_str(), s);
1625 cta.vec_vtdbs.push_back(te);
1629 // tag 0x7e, OUI 3A-02-92 (VESA)
1631 void edid_state::parse_displayid_vesa(const unsigned char *x)
1633 check_displayid_datablock_revision(x[1]);
1635 if (!check_displayid_datablock_length(x, 5, 7))
1636 return;
1638 unsigned len = x[2];
1639 x += 6;
1640 printf(" Data Structure Type: ");
1641 switch (x[0] & 7) {
1642 case 0: printf("eDP\n"); break;
1643 case 1: printf("DP\n"); break;
1644 default: printf("Reserved (%d)\n", x[0] & 7); break;
1647 if ((x[0] >> 3) & 15)
1648 warn("Reserved bits 6:3 (%d) are not 0.\n", (x[0] >> 3) & 15);
1650 printf(" Default Colorspace and EOTF Handling: %s\n",
1651 (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1653 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1654 x[1] & 0xf);
1655 if ((x[1] & 0xf) > 8)
1656 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1658 if ((x[1] >> 4) & 1)
1659 warn("Reserved bit 4 is not 0.\n");
1661 printf(" Multi-SST Operation: ");
1662 switch ((x[1] >> 5) & 3) {
1663 case 0: printf("Not Supported\n"); break;
1664 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1665 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1666 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1669 if ((x[1] >> 7) & 1)
1670 warn("Reserved bit 7 is not 0.\n");
1672 if (len >= 7) {
1673 double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1674 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1678 // tag 0x7f, OUI 00-10-FA (Apple)
1680 void edid_state::parse_displayid_apple(const unsigned char *x)
1682 int length = x[2] - 3;
1684 x += 6;
1686 // Based on the very limited information I found here:
1687 // https://opensource.apple.com/source/IOKitUser/IOKitUser-1445.40.1/graphics.subproj/IODisplayLib.c
1688 switch (x[0]) {
1689 case 1:
1690 printf(" Type: BLC Info/Corrections, Version: %u\n", x[1]);
1691 break;
1692 default:
1693 printf(" Type: %u, Version: %u\n", x[0], x[1]);
1694 break;
1696 hex_block(" ", x + 2, length - 2);
1699 // tag 0x81
1701 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1703 check_displayid_datablock_revision(x[1]);
1705 unsigned len = x[2];
1706 unsigned i;
1708 if (len > 248) {
1709 fail("Length is > 248.\n");
1710 len = 248;
1712 x += 3;
1714 for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1715 cta_block(x + i, dispid.found_tags);
1718 if (i != len)
1719 fail("Length is %u instead of %u.\n", len, i);
1722 // DisplayID main
1724 std::string edid_state::product_type(unsigned char x, bool heading)
1726 std::string headingstr;
1728 if (dispid.version < 0x20) {
1729 headingstr = "Display Product Type";
1730 if (heading) return headingstr;
1731 dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1732 switch (x) {
1733 case 0: return "Extension Section";
1734 case 1: return "Test Structure; test equipment only";
1735 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1736 case 3: return "Standalone display device";
1737 case 4: return "Television receiver";
1738 case 5: return "Repeater/translator";
1739 case 6: return "DIRECT DRIVE monitor";
1740 default: break;
1742 } else {
1743 headingstr = "Display Product Primary Use Case";
1744 if (heading) return headingstr;
1745 dispid.is_display = x >= 2 && x <= 8;
1746 dispid.is_arvr = x >= 7 && x <= 8;
1747 switch (x) {
1748 case 0: return "Same primary use case as the base section";
1749 case 1: return "Test Structure; test equipment only";
1750 case 2: return "None of the listed primary use cases; generic display";
1751 case 3: return "Television (TV) display";
1752 case 4: return "Desktop productivity display";
1753 case 5: return "Desktop gaming display";
1754 case 6: return "Presentation display";
1755 case 7: return "Head-mounted Virtual Reality (VR) display";
1756 case 8: return "Head-mounted Augmented Reality (AR) display";
1757 default: break;
1760 fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1761 return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1764 void edid_state::preparse_displayid_block(unsigned char *x)
1766 bool update_checksum = false;
1767 unsigned length = x[2];
1768 unsigned offset = 5;
1770 if (length > 121)
1771 length = 121;
1773 dispid.preparsed_displayid_blocks++;
1774 while (length > 0) {
1775 unsigned tag = x[offset];
1776 unsigned len = x[offset + 2];
1778 switch (tag) {
1779 case 0x00:
1780 case 0x20:
1781 if (replace_unique_ids &&
1782 (x[offset + 0x08] || x[offset + 0x09] ||
1783 x[offset + 0x0a] || x[offset + 0x0b])) {
1784 // Replace by 123456
1785 x[offset + 0x08] = 0x40;
1786 x[offset + 0x09] = 0xe2;
1787 x[offset + 0x0a] = 0x01;
1788 x[offset + 0x0b] = 0x00;
1789 update_checksum = true;
1791 if (replace_unique_ids && x[offset + 0x0c] != 0xff) {
1792 x[offset + 0x0c] = 0;
1793 x[offset + 0x0d] = 0;
1794 update_checksum = true;
1796 break;
1797 case 0x12:
1798 case 0x28:
1799 if (replace_unique_ids &&
1800 (x[offset + 0x15] || x[offset + 0x16] ||
1801 x[offset + 0x17] || x[offset + 0x18])) {
1802 // Replace by 123456
1803 x[offset + 0x15] = 0x40;
1804 x[offset + 0x16] = 0xe2;
1805 x[offset + 0x17] = 0x01;
1806 x[offset + 0x18] = 0x00;
1807 update_checksum = true;
1809 break;
1810 case 0x29:
1811 if (replace_unique_ids) {
1812 update_checksum = true;
1813 memset(x + offset + 3, 0, 16);
1815 break;
1816 case 0x02:
1817 dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1818 break;
1819 case 0x0e:
1820 dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1821 break;
1822 default:
1823 break;
1826 if (length < 3)
1827 break;
1829 if (length < len + 3)
1830 break;
1832 if (!tag && !len)
1833 break;
1835 length -= len + 3;
1836 offset += len + 3;
1838 if (update_checksum) {
1839 replace_checksum(x + 1, x[2] + 5);
1840 replace_checksum(x, EDID_PAGE_SIZE);
1844 unsigned edid_state::displayid_block(const unsigned version, const unsigned char *x, unsigned length)
1846 unsigned i;
1847 unsigned tag = x[0];
1848 unsigned tag_version = (tag < 0x20) ? 1 : (tag < 0x7f) ? 2 : (tag < 0x80) ? 1 : 0;
1849 bool dooutputname = true;
1850 unsigned len = (length < 3) ? 0 : x[2];
1851 bool hasoui = false;
1852 unsigned ouinum;
1854 switch (tag) {
1855 // DisplayID 1.3:
1856 case 0x00:
1857 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1858 x + 3, len, &ouinum, true, true, true);
1859 dooutputname = false;
1860 hasoui = true;
1861 break;
1862 case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1863 case 0x02: data_block = "Color Characteristics Data Block"; break;
1864 case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1865 case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1866 case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1867 case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1868 case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1869 case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1870 case 0x09: data_block = "Video Timing Range Data Block"; break;
1871 case 0x0a: data_block = "Product Serial Number Data Block"; break;
1872 case 0x0b: data_block = "GP ASCII String Data Block"; break;
1873 case 0x0c: data_block = "Display Device Data Data Block"; break;
1874 case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1875 case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1876 case 0x0f: data_block = "Display Interface Data Block"; break;
1877 case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1878 case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1879 case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1880 case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1881 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1882 // DisplayID 2.0
1883 case 0x20:
1884 data_block_oui("Product Identification Data Block (" + utohex(tag) + ")",
1885 x + 3, len, &ouinum, false, false, true);
1886 dooutputname = false;
1887 hasoui = true;
1888 break;
1889 case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1890 case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1891 case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1892 case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1893 case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1894 case 0x26: data_block = "Display Interface Features Data Block"; break;
1895 case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1896 case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1897 case 0x29: data_block = "ContainerID Data Block"; break;
1898 case 0x2b: data_block = "Adaptive Sync Data Block"; break;
1899 case 0x2c: data_block = "ARVR_HMD Data Block"; break;
1900 case 0x2d: data_block = "ARVR_Layer Data Block"; break;
1901 case 0x2e: data_block = "Brightness Luminance Range Data Block"; break;
1902 case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1903 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1904 case 0x7e: // DisplayID 2.0
1905 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1906 x + 3, len, &ouinum, false, false, true);
1907 dooutputname = false;
1908 hasoui = true;
1909 tag |= ouinum;
1910 break;
1911 case 0x7f: // DisplayID 1.3
1912 data_block_oui("Vendor-Specific Data Block (" + utohex(tag) + ")",
1913 x + 3, len, &ouinum, false, true, true);
1914 dooutputname = false;
1915 hasoui = true;
1916 tag |= ouinum;
1917 break;
1918 // 0x80 RESERVED
1919 case 0x81: data_block = "CTA-861 DisplayID Data Block"; break;
1920 // 0x82 .. 0xff RESERVED
1921 default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ", length " + std::to_string(len) + ")"; break;
1924 if (length < 3) {
1925 // Report a problem when the remaining bytes are not 0.
1926 data_block.clear(); // Probably not a Data Block so clear this.
1927 if (tag || (length > 1 && x[1])) {
1928 printf(" Filler:\n");
1929 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length);
1930 hex_block(" ", x, length);
1932 return length;
1935 if (length < len + 3) {
1936 data_block.clear(); // Probably not a Data Block so clear this.
1937 printf(" Filler:\n");
1938 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1939 hex_block(" ", x, length);
1940 return length;
1943 if (!tag && !len) {
1944 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1945 data_block.clear(); // Probably not a Product Identification Data Block so clear this.
1946 if (!memchk(x, length)) {
1947 printf(" Filler:\n");
1948 fail("Non-0 filler bytes in the DisplayID block.\n");
1949 hex_block(" ", x, length);
1951 return length;
1954 if (dooutputname && data_block.length())
1955 printf(" %s:\n", data_block.c_str());
1957 if (version >= 0x20 && tag_version == 1)
1958 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1959 version >> 4, version & 0xf);
1960 if (version < 0x20 && tag_version == 2)
1961 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1962 version >> 4, version & 0xf);
1964 unsigned block_rev = x[1] & 0x07;
1966 switch (tag) {
1967 case 0x00: parse_displayid_product_id(x); break;
1968 case 0x01: parse_displayid_parameters(x); break;
1969 case 0x02: parse_displayid_color_characteristics(x); break;
1970 case 0x03:
1971 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1972 for (i = 0; i < len / 20; i++)
1973 parse_displayid_type_1_7_timing(&x[3 + (i * 20)], false, block_rev);
1974 break;
1975 case 0x04:
1976 check_displayid_datablock_revision(x[1]);
1977 for (i = 0; i < len / 11; i++)
1978 parse_displayid_type_2_timing(&x[3 + (i * 11)]);
1979 break;
1980 case 0x05:
1981 check_displayid_datablock_revision(x[1], 0, block_rev & 1);
1982 for (i = 0; i < len / 3; i++)
1983 parse_displayid_type_3_timing(&x[3 + (i * 3)]);
1984 break;
1985 case 0x06:
1986 check_displayid_datablock_revision(x[1], 0xc0, 1);
1987 for (i = 0; i < len; i++)
1988 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6, x[3 + i]);
1989 break;
1990 case 0x07:
1991 check_displayid_datablock_revision(x[1]);
1992 for (i = 0; i < min(len, 10) * 8; i++)
1993 if (x[3 + i / 8] & (1 << (i % 8))) {
1994 char type[16];
1995 sprintf(type, "DMT 0x%02x", i + 1);
1996 print_timings(" ", find_dmt_id(i + 1), type);
1998 break;
1999 case 0x08:
2000 check_displayid_datablock_revision(x[1]);
2001 for (i = 0; i < min(len, 8) * 8; i++)
2002 if (x[3 + i / 8] & (1 << (i % 8))) {
2003 char type[16];
2004 sprintf(type, "VIC %3u", i + 1);
2005 print_timings(" ", find_vic_id(i + 1), type);
2007 break;
2008 case 0x09: parse_displayid_video_timing_range_limits(x); break;
2009 case 0x0a:
2010 case 0x0b: parse_displayid_string(x); break;
2011 case 0x0c: parse_displayid_display_device(x); break;
2012 case 0x0d: parse_displayid_intf_power_sequencing(x); break;
2013 case 0x0e: parse_displayid_transfer_characteristics(x); break;
2014 case 0x0f: parse_displayid_display_intf(x); break;
2015 case 0x10: parse_displayid_stereo_display_intf(x); break;
2016 case 0x11:
2017 check_displayid_datablock_revision(x[1]);
2018 for (i = 0; i < len / 7; i++)
2019 parse_displayid_type_5_timing(&x[3 + (i * 7)]);
2020 break;
2021 case 0x12: parse_displayid_tiled_display_topology(x, false); break;
2022 case 0x13:
2023 check_displayid_datablock_revision(x[1]);
2024 for (i = 0; i < len; i += (x[3 + i + 2] & 0x40) ? 17 : 14)
2025 parse_displayid_type_6_timing(&x[3 + i]);
2026 break;
2027 case 0x20: parse_displayid_product_id(x); break;
2028 case 0x21:
2029 if (block_rev >= 1)
2030 check_displayid_datablock_revision(x[1], 0x80, 1);
2031 else
2032 check_displayid_datablock_revision(x[1], 0x80, 0);
2033 parse_displayid_parameters_v2(x, block_rev);
2034 break;
2035 case 0x22: {
2036 unsigned sz = 20;
2038 if (block_rev >= 2)
2039 check_displayid_datablock_revision(x[1], 0x08, 2);
2040 else if (block_rev == 1)
2041 check_displayid_datablock_revision(x[1], 0x08, 1);
2042 else
2043 check_displayid_datablock_revision(x[1]);
2044 sz += (x[1] & 0x70) >> 4;
2045 if (block_rev >= 1 && (x[1] & 0x08))
2046 printf(" These timings support DSC pass-through\n");
2047 for (i = 0; i < len / sz; i++)
2048 parse_displayid_type_1_7_timing(&x[3 + i * sz], true, block_rev);
2049 break;
2051 case 0x23:
2052 if (block_rev)
2053 check_displayid_datablock_revision(x[1], 0xe8, 1);
2054 else
2055 check_displayid_datablock_revision(x[1], 0xc8);
2056 if (x[1] & 0x08) {
2057 for (i = 0; i < len / 2; i++)
2058 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
2059 x[3 + i * 2] |
2060 (x[4 + i * 2] << 8));
2061 } else {
2062 for (i = 0; i < len; i++)
2063 parse_displayid_type_4_8_timing((x[1] & 0xc0) >> 6,
2064 x[3 + i]);
2066 break;
2067 case 0x24:
2068 check_displayid_datablock_revision(x[1]);
2069 for (i = 0; i < len / 6; i++)
2070 parse_displayid_type_9_timing(&x[3 + i * 6]);
2071 break;
2072 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x); break;
2073 case 0x26: parse_displayid_interface_features(x); break;
2074 case 0x27: parse_displayid_stereo_display_intf(x); break;
2075 case 0x28: parse_displayid_tiled_display_topology(x, true); break;
2076 case 0x29: parse_displayid_ContainerID(x); break;
2077 case 0x2b: parse_displayid_adaptive_sync(x); break;
2078 case 0x2c: parse_displayid_arvr_hmd(x); break;
2079 case 0x2d: parse_displayid_arvr_layer(x); break;
2080 case 0x2e: parse_displayid_brightness_lum_range(x); break;
2081 case 0x32: {
2082 unsigned sz = 6 + ((x[1] & 0x70) >> 4);
2084 check_displayid_datablock_revision(x[1], 0x70);
2085 if (sz > 8)
2086 fail("Invalid descriptor size %u.\n", sz);
2088 for (i = 0; i < len / sz; i++)
2089 parse_displayid_type_10_timing(&x[3 + i * sz], sz);
2090 break;
2092 case 0x7e|kOUI_VESA: parse_displayid_vesa(x); break;
2093 case 0x7f|kOUI_Apple: parse_displayid_apple(x); break;
2094 case 0x81: parse_displayid_cta_data_block(x); break;
2095 default: hex_block(" ", x + 3 + (hasoui ? 3 : 0), (len > (hasoui ? 3 : 0)) ? len - (hasoui ? 3 : 0) : 0); break;
2098 if ((tag == 0x00 || tag == 0x20) &&
2099 (!dispid.is_base_block || dispid.block_number > 0))
2100 fail("%s is required to be the first DisplayID Data Block.\n",
2101 data_block.c_str());
2103 dispid.block_number++;
2104 return len + 3;
2107 void edid_state::parse_displayid_block(const unsigned char *x)
2109 unsigned version = x[1];
2110 unsigned length = x[2];
2111 unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
2112 unsigned ext_count = x[4];
2114 printf(" Version: %u.%u\n Extension Count: %u\n",
2115 version >> 4, version & 0xf, ext_count);
2117 if (dispid.is_base_block) {
2118 dispid.version = version;
2119 printf(" %s: %s\n", product_type(prod_type, true).c_str(),
2120 product_type(prod_type, false).c_str());
2121 if (!prod_type)
2122 fail("DisplayID Base Block has no product type.\n");
2123 if (ext_count != dispid.preparsed_displayid_blocks - 1)
2124 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
2125 ext_count,
2126 ext_count > 1 ? "s" : "",
2127 dispid.preparsed_displayid_blocks - 1);
2128 } else {
2129 if (prod_type)
2130 fail("Product Type should be 0 in extension block.\n");
2131 if (ext_count)
2132 fail("Extension Count should be 0 in extension block.\n");
2133 if (version != dispid.version)
2134 fail("Got version %u.%u, expected %u.%u.\n",
2135 version >> 4, version & 0xf,
2136 dispid.version >> 4, dispid.version & 0xf);
2139 if (length > 121) {
2140 fail("DisplayID length %d is greater than 121.\n", length);
2141 length = 121;
2144 unsigned len;
2145 for (const unsigned char *y = x + 5; length > 0; y += len) {
2146 len = displayid_block(version, y, length);
2147 length -= len;
2151 * DisplayID length field is number of following bytes
2152 * but checksum is calculated over the entire structure
2153 * (excluding DisplayID-in-EDID magic byte)
2155 data_block.clear();
2156 do_checksum(" ", x + 1, x[2] + 5, x[2] + 4);
2158 unused_bytes = 0x7f - (1 + x[2] + 5);
2159 if (!memchk(x + 1 + x[2] + 5, unused_bytes)) {
2160 data_block = "Padding";
2161 fail("Contains non-zero bytes.\n");
2163 dispid.is_base_block = false;
2166 void edid_state::check_displayid_blocks()
2168 data_block = "DisplayID";
2169 if (!dispid.has_product_identification &&
2170 (native_dispid || dispid.has_tiled_display_topology))
2171 fail("Missing DisplayID Product Identification Data Block.\n");
2172 if (dispid.is_display && (native_dispid || !dispid.has_display_parameters))
2173 fail("Missing DisplayID Display Parameters Data Block.\n");
2174 if (dispid.is_display && !dispid.has_display_interface_features &&
2175 (native_dispid || dispid.has_ycbcr_420))
2176 fail("Missing DisplayID Display Interface Features Data Block.\n");
2177 if (native_dispid && dispid.is_arvr && !dispid.has_arvr_hdm)
2178 fail("Missing DisplayID ARVR_HMD Data Block.\n");
2179 if (native_dispid && dispid.is_arvr && !dispid.has_arvr_layer)
2180 fail("Missing DisplayID ARVR_Layer Data Block.\n");
2181 if (dispid.has_stereo && !dispid.has_stereo_display_interface)
2182 fail("Missing DisplayID Stereo Display Interface Data Block.\n");
2183 if (dispid.is_display && !dispid.has_type_1_7)
2184 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
2185 dispid.version >= 0x20 ? "VII" : "I");
2186 if (dispid.preferred_timings.empty())
2187 fail("DisplayID expects at least one preferred timing.\n");
2188 if (cta.image_width && dispid.image_width &&
2189 (cta.image_width != dispid.image_width ||
2190 cta.image_height != dispid.image_height))
2191 fail("Image size mismatch: CTA-861: %.1fx%.1fmm DisplayID: %.1fx%.1fmm.\n",
2192 cta.image_width / 10.0, cta.image_height / 10.0,
2193 dispid.image_width / 10.0, dispid.image_height / 10.0);
2194 if (dispid.image_width && dispid.image_width < 25600 && dispid.image_height < 25600 &&
2195 (abs((int)dispid.image_width - (int)base.max_display_width_mm * 10) >= 100 ||
2196 abs((int)dispid.image_height - (int)base.max_display_height_mm * 10) >= 100))
2197 fail("Image size mismatch: DisplayID: %.1fx%.1fmm Base EDID: %u.0x%u.0mm.\n",
2198 dispid.image_width / 10.0, dispid.image_height / 10.0,
2199 base.max_display_width_mm, base.max_display_height_mm);