1 // SPDX-License-Identifier: MIT
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>
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
};
20 static void print_flags(const char *label
, unsigned char flag_byte
,
21 const char **flags
, bool reverse
= false)
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
))) {
34 printf("%s", flags
[i
]);
36 printf("Undefined (%u)", i
);
43 void edid_state::check_displayid_datablock_revision(unsigned char hdr
,
44 unsigned char valid_flags
,
47 unsigned char revision
= hdr
& 7;
48 unsigned char flags
= hdr
& ~7 & ~valid_flags
;
51 warn("Unexpected revision (%u != %u).\n", revision
, rev
);
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
);
72 if (len
> payloaddumpstart
)
73 hex_block(" ", x
+ 3 + payloaddumpstart
, len
- payloaddumpstart
);
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);
87 if (hide_serial_numbers
)
88 printf(" Serial Number: ...\n");
90 printf(" Serial Number: %u\n", sn
);
92 unsigned week
= x
[12];
93 unsigned year
= 2000 + x
[13];
95 week
== 0xff ? "Model Year" : "Year of Manufacture", year
);
96 if (week
&& week
<= 0x36)
97 printf(", Week %u", week
);
102 memcpy(buf
, x
+ 15, x
[14]);
104 printf(" Product ID: %s\n", buf
);
110 static const char *feature_support_flags
[] = {
112 "Support ACP, ISRC1, or ISRC2packets",
113 "Fixed pixel format",
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
)
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::parse_displayid_parameters(const unsigned char *x
)
135 check_displayid_datablock_revision(x
[1]);
137 if (!check_displayid_datablock_length(x
, 12, 12))
140 dispid
.has_display_parameters
= true;
141 printf(" Image size: %.1f mm x %.1f mm\n",
142 ((x
[4] << 8) + x
[3]) / 10.0,
143 ((x
[6] << 8) + x
[5]) / 10.0);
144 printf(" Pixels: %d x %d\n",
145 (x
[8] << 8) + x
[7], (x
[10] << 8) + x
[9]);
146 print_flag_lines(" ", " Feature support flags:",
147 x
[11], feature_support_flags
);
150 printf(" Gamma: %.2f\n", ((x
[12] + 100.0) / 100.0));
151 printf(" Aspect ratio: %.2f\n", ((x
[13] + 100.0) / 100.0));
152 printf(" Dynamic bpc native: %d\n", (x
[14] & 0xf) + 1);
153 printf(" Dynamic bpc overall: %d\n", ((x
[14] >> 4) & 0xf) + 1);
158 static const char *std_colorspace_ids
[] = {
166 "Adobe Wide Gamut RGB",
170 static double fp2d(unsigned short fp
)
175 void edid_state::parse_displayid_color_characteristics(const unsigned char *x
)
177 check_displayid_datablock_revision(x
[1], 0xf8, 1);
179 unsigned cie_year
= (x
[1] & 0x80) ? 1976 : 1931;
180 unsigned xfer_id
= (x
[1] >> 3) & 0x0f;
181 unsigned num_whitepoints
= x
[3] & 0x0f;
182 unsigned num_primaries
= (x
[3] >> 4) & 0x07;
183 bool temporal_color
= x
[3] & 0x80;
186 printf(" Uses %s color\n", temporal_color
? "temporal" : "spatial");
187 printf(" Uses %u CIE (x, y) coordinates\n", cie_year
);
189 printf(" Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id
);
190 if (!(dispid
.preparsed_xfer_ids
& (1 << xfer_id
)))
191 fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id
);
193 if (!num_primaries
) {
194 printf(" Uses color space %s\n",
195 x
[4] >= ARRAY_SIZE(std_colorspace_ids
) ? "Reserved" :
196 std_colorspace_ids
[x
[4]]);
199 for (unsigned i
= 0; i
< num_primaries
; i
++) {
200 unsigned idx
= offset
+ 3 * i
;
202 printf(" Primary #%u: (%.4f, %.4f)\n", i
,
203 fp2d(x
[idx
] | ((x
[idx
+ 1] & 0x0f) << 8)),
204 fp2d(((x
[idx
+ 1] & 0xf0) >> 4) | (x
[idx
+ 2] << 4)));
206 offset
+= 3 * num_primaries
;
207 for (unsigned i
= 0; i
< num_whitepoints
; i
++) {
208 unsigned idx
= offset
+ 3 * i
;
210 printf(" White point #%u: (%.4f, %.4f)\n", i
,
211 fp2d(x
[idx
] | ((x
[idx
+ 1] & 0x0f) << 8)),
212 fp2d(((x
[idx
+ 1] & 0xf0) >> 4) | (x
[idx
+ 2] << 4)));
218 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x
,
219 bool type7
, unsigned block_rev
, bool is_cta
)
221 struct timings t
= {};
223 std::string
s("aspect ");
225 dispid
.has_type_1_7
= true;
226 t
.pixclk_khz
= (type7
? 1 : 10) * (1 + (x
[0] + (x
[1] << 8) + (x
[2] << 16)));
227 switch (x
[3] & 0xf) {
230 t
.hratio
= t
.vratio
= 1;
272 fail("Unknown aspect 0x%02x.\n", x
[3] & 0xf);
275 switch ((x
[3] >> 5) & 0x3) {
277 s
+= ", no 3D stereo";
283 s
+= ", 3D stereo depends on user action";
287 fail("Reserved stereo 0x03.\n");
290 if (block_rev
>= 2 && (x
[3] & 0x80))
291 s
+= ", YCbCr 4:2:0";
293 t
.hact
= 1 + (x
[4] | (x
[5] << 8));
294 hbl
= 1 + (x
[6] | (x
[7] << 8));
295 t
.hfp
= 1 + (x
[8] | ((x
[9] & 0x7f) << 8));
296 t
.hsync
= 1 + (x
[10] | (x
[11] << 8));
297 t
.hbp
= hbl
- t
.hfp
- t
.hsync
;
298 if ((x
[9] >> 7) & 0x1)
299 t
.pos_pol_hsync
= true;
300 t
.vact
= 1 + (x
[12] | (x
[13] << 8));
301 vbl
= 1 + (x
[14] | (x
[15] << 8));
302 t
.vfp
= 1 + (x
[16] | ((x
[17] & 0x7f) << 8));
303 t
.vsync
= 1 + (x
[18] | (x
[19] << 8));
304 t
.vbp
= vbl
- t
.vfp
- t
.vsync
;
305 if ((x
[17] >> 7) & 0x1)
306 t
.pos_pol_vsync
= true;
314 if (block_rev
< 2 && (x
[3] & 0x80)) {
316 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
319 print_timings(" ", &t
, "DTD", s
.c_str(), true);
321 timings_ext
te(t
, "DTD", s
);
322 cta
.vec_vtdbs
.push_back(te
);
324 // Only use a T7VTDB if is cannot be expressed by a
326 if (t
.hact
<= 4095 && t
.vact
<= 4095 &&
327 t
.pixclk_khz
<= 655360 && !(x
[3] & 0xe0)) {
328 fail("This T7VTDB can be represented as an 18-byte DTD.\n");
331 unsigned htot
= t
.hact
+ t
.hfp
+ t
.hsync
+ t
.hbp
;
332 unsigned vtot
= t
.vact
+ t
.vfp
+ t
.vsync
+ t
.vbp
;
333 unsigned refresh
= (t
.pixclk_khz
* 1000ULL) / (htot
* vtot
);
335 for (unsigned rb
= RB_NONE
; rb
<= RB_CVT_V3
; rb
++) {
336 timings cvt_t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, rb
);
337 if (match_timings(t
, cvt_t
)) {
338 fail("This T7VTDB can be represented as a T10VTDB.\n");
342 timings cvt_t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, RB_CVT_V3
,
344 if (match_timings(t
, cvt_t
))
345 fail("This T7VTDB can be represented as a T10VTDB.\n");
351 void edid_state::parse_displayid_type_2_timing(const unsigned char *x
)
353 struct timings t
= {};
355 std::string
s("aspect ");
357 t
.pixclk_khz
= 10 * (1 + (x
[0] + (x
[1] << 8) + (x
[2] << 16)));
358 t
.hact
= 8 + 8 * (x
[4] | ((x
[5] & 0x01) << 8));
359 hbl
= 8 + 8 * ((x
[5] & 0xfe) >> 1);
360 t
.hfp
= 8 + 8 * ((x
[6] & 0xf0) >> 4);
361 t
.hsync
= 8 + 8 * (x
[6] & 0xf);
362 t
.hbp
= hbl
- t
.hfp
- t
.hsync
;
363 if ((x
[3] >> 3) & 0x1)
364 t
.pos_pol_hsync
= true;
365 t
.vact
= 1 + (x
[7] | ((x
[8] & 0xf) << 8));
367 t
.vfp
= 1 + (x
[10] >> 4);
368 t
.vsync
= 1 + (x
[10] & 0xf);
369 t
.vbp
= vbl
- t
.vfp
- t
.vsync
;
370 if ((x
[17] >> 2) & 0x1)
371 t
.pos_pol_vsync
= true;
382 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
384 switch ((x
[3] >> 5) & 0x3) {
386 s
+= ", no 3D stereo";
392 s
+= ", 3D stereo depends on user action";
396 fail("Reserved stereo 0x03.\n");
401 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
404 print_timings(" ", &t
, "DTD", s
.c_str(), true);
409 void edid_state::parse_displayid_type_3_timing(const unsigned char *x
)
411 struct timings t
= {};
412 std::string
s("aspect ");
414 switch (x
[0] & 0xf) {
417 t
.hratio
= t
.vratio
= 1;
459 fail("Unknown aspect 0x%02x.\n", x
[0] & 0xf);
463 t
.rb
= ((x
[0] & 0x70) >> 4) == 1 ? RB_CVT_V1
: RB_NONE
;
464 t
.hact
= 8 + 8 * x
[1];
465 t
.vact
= t
.hact
* t
.vratio
/ t
.hratio
;
467 edid_cvt_mode(1 + (x
[2] & 0x7f), t
);
471 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
474 print_timings(" ", &t
, "CVT", s
.c_str());
479 void edid_state::parse_displayid_type_4_8_timing(unsigned char type
, unsigned short id
, bool is_cta
)
481 const struct timings
*t
= NULL
;
485 case 0: t
= find_dmt_id(id
); sprintf(type_name
, "DMT 0x%02x", id
); break;
486 case 1: t
= find_vic_id(id
); sprintf(type_name
, "VIC %3u", id
); break;
487 case 2: t
= find_hdmi_vic_id(id
); sprintf(type_name
, "HDMI VIC %u", id
); break;
491 print_timings(" ", t
, type_name
);
492 if (t
&& is_cta
&& !cta
.t8vtdb
.is_valid()) {
493 timings_ext
te(*t
, type_name
, "");
500 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x
)
502 check_displayid_datablock_revision(x
[1]);
504 if (!check_displayid_datablock_length(x
, 15, 15))
506 printf(" Pixel Clock: %.3f-%.3f MHz\n",
507 (double)((x
[3] | (x
[4] << 8) | (x
[5] << 16)) + 1) / 100.0,
508 (double)((x
[6] | (x
[7] << 8) | (x
[8] << 16)) + 1) / 100.0);
509 printf(" Horizontal Frequency: %u-%u kHz\n", x
[9], x
[10]);
510 printf(" Minimum Horizontal Blanking: %u pixels\n", x
[11] | (x
[12] << 8));
511 printf(" Vertical Refresh: %u-%u Hz\n", x
[13], x
[14]);
512 printf(" Minimum Vertical Blanking: %u lines\n", x
[15] | (x
[16] << 8));
514 printf(" Supports Interlaced\n");
516 printf(" Supports CVT\n");
518 printf(" Supports CVT Reduced Blanking\n");
520 printf(" Discrete frequency display device\n");
525 void edid_state::parse_displayid_string(const unsigned char *x
)
527 check_displayid_datablock_revision(x
[1]);
528 if (check_displayid_datablock_length(x
))
529 printf(" Text: '%s'\n", extract_string(x
+ 3, x
[2]));
534 void edid_state::parse_displayid_display_device(const unsigned char *x
)
536 check_displayid_datablock_revision(x
[1]);
538 if (!check_displayid_datablock_length(x
, 13, 13))
541 printf(" Display Device Technology: ");
543 case 0x00: printf("Monochrome CRT\n"); break;
544 case 0x01: printf("Standard tricolor CRT\n"); break;
545 case 0x02: printf("Other/undefined CRT\n"); break;
546 case 0x10: printf("Passive matrix TN\n"); break;
547 case 0x11: printf("Passive matrix cholesteric LC\n"); break;
548 case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
549 case 0x13: printf("Other passive matrix LC type\n"); break;
550 case 0x14: printf("Active-matrix TN\n"); break;
551 case 0x15: printf("Active-matrix IPS (all types)\n"); break;
552 case 0x16: printf("Active-matrix VA (all types)\n"); break;
553 case 0x17: printf("Active-matrix OCB\n"); break;
554 case 0x18: printf("Active-matrix ferroelectric\n"); break;
555 case 0x1f: printf("Other LC type\n"); break;
556 case 0x20: printf("DC plasma\n"); break;
557 case 0x21: printf("AC plasma\n"); break;
559 switch (x
[3] & 0xf0) {
560 case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
561 case 0x40: printf("Inorganic LED\n"); break;
562 case 0x50: printf("Organic LED/OEL\n"); break;
563 case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
564 case 0x70: printf("Electrophoretic\n"); break;
565 case 0x80: printf("Electrochromic\n"); break;
566 case 0x90: printf("Electromechanical\n"); break;
567 case 0xa0: printf("Electrowetting\n"); break;
568 case 0xf0: printf("Other type not defined here\n"); break;
570 printf(" Display operating mode: ");
572 case 0x00: printf("Direct-view reflective, ambient light\n"); break;
573 case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
574 case 0x02: printf("Direct-view reflective, uses light source\n"); break;
575 case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
576 case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
577 case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
578 case 0x06: printf("Direct-view emissive\n"); break;
579 case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
580 case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
581 case 0x09: printf("Transparent display, ambient light\n"); break;
582 case 0x0a: printf("Transparent emissive display\n"); break;
583 case 0x0b: printf("Projection device using reflective light modulator\n"); break;
584 case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
585 case 0x0d: printf("Projection device using emissive image transducer\n"); break;
586 default: printf("Reserved\n"); break;
589 printf(" The backlight may be switched on and off\n");
591 printf(" The backlight's intensity can be controlled\n");
592 unsigned w
= x
[5] | (x
[6] << 8);
593 unsigned h
= x
[7] | (x
[8] << 8);
595 printf(" Display native pixel format: %ux%u\n", w
+ 1, h
+ 1);
596 dispid
.native_width
= w
+ 1;
597 dispid
.native_height
= h
+ 1;
599 fail("Invalid Native Pixel Format %ux%u.\n", w
, h
);
601 printf(" Aspect ratio and orientation:\n");
602 printf(" Aspect Ratio: %.2f\n", (100 + x
[9]) / 100.0);
603 unsigned char v
= x
[0x0a];
604 printf(" Default Orientation: ");
605 switch ((v
& 0xc0) >> 6) {
606 case 0x00: printf("Landscape\n"); break;
607 case 0x01: printf("Portrait\n"); break;
608 case 0x02: printf("Not Fixed\n"); break;
609 case 0x03: printf("Undefined\n"); break;
611 printf(" Rotation Capability: ");
612 switch ((v
& 0x30) >> 4) {
613 case 0x00: printf("None\n"); break;
614 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
615 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
616 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
618 printf(" Zero Pixel Location: ");
619 switch ((v
& 0x0c) >> 2) {
620 case 0x00: printf("Upper Left\n"); break;
621 case 0x01: printf("Upper Right\n"); break;
622 case 0x02: printf("Lower Left\n"); break;
623 case 0x03: printf("Lower Right\n"); break;
625 printf(" Scan Direction: ");
627 case 0x00: printf("Not defined\n"); break;
628 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
629 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
630 case 0x03: printf("Reserved\n");
631 fail("Scan Direction used the reserved value 0x03.\n");
634 printf(" Sub-pixel layout/configuration/shape: ");
636 case 0x00: printf("Not defined\n"); break;
637 case 0x01: printf("RGB vertical stripes\n"); break;
638 case 0x02: printf("RGB horizontal stripes\n"); break;
639 case 0x03: printf("Vertical stripes using primary order\n"); break;
640 case 0x04: printf("Horizontal stripes using primary order\n"); break;
641 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
642 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
643 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
644 case 0x08: printf("Mosaic\n"); break;
645 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
646 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
647 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
648 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
649 default: printf("Reserved\n"); break;
651 printf(" Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
652 (double)(x
[0x0c]) / 100.0, (double)(x
[0x0d]) / 100.0);
653 printf(" Color bit depth: %u\n", x
[0x0e] & 0x0f);
655 printf(" Response time for %s transition: %u ms\n",
656 (v
& 0x80) ? "white-to-black" : "black-to-white", v
& 0x7f);
661 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x
)
663 check_displayid_datablock_revision(x
[1]);
665 if (!check_displayid_datablock_length(x
, 6, 6))
668 printf(" Power Sequence T1 Range: %.1f-%u.0 ms\n", (x
[3] >> 4) / 10.0, (x
[3] & 0xf) * 2);
669 printf(" Power Sequence T2 Range: 0.0-%u.0 ms\n", (x
[4] & 0x3f) * 2);
670 printf(" Power Sequence T3 Range: 0.0-%u.0 ms\n", (x
[5] & 0x3f) * 2);
671 printf(" Power Sequence T4 Min: %u.0 ms\n", (x
[6] & 0x7f) * 10);
672 printf(" Power Sequence T5 Min: %u.0 ms\n", (x
[7] & 0x3f) * 10);
673 printf(" Power Sequence T6 Min: %u.0 ms\n", (x
[8] & 0x3f) * 10);
678 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x
)
680 check_displayid_datablock_revision(x
[1], 0xf0, 1);
682 unsigned xfer_id
= x
[1] >> 4;
683 bool first_is_white
= x
[3] & 0x80;
684 bool four_param
= x
[3] & 0x20;
687 printf(" Transfer Characteristics Data Block Identifier: %u\n", xfer_id
);
688 if (!(dispid
.preparsed_color_ids
& (1 << xfer_id
)))
689 fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id
);
692 printf(" The first curve is the 'white' transfer characteristic\n");
694 printf(" Individual response curves\n");
697 unsigned len
= x
[2] - 1;
699 for (unsigned i
= 0; len
; i
++) {
700 if ((x
[3] & 0x80) && !i
)
701 printf(" White curve: ");
703 printf(" Response curve #%u:",
705 unsigned samples
= x
[offset
];
708 fail("Expected 5 samples.\n");
709 printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
710 x
[offset
+ 1], x
[offset
+ 2], x
[offset
+ 3], x
[offset
+ 4],
711 (double)(x
[offset
+ 5] + 100.0) / 100.0);
716 // The spec is not very clear about the number of samples:
717 // should this be interpreted as the actual number of
718 // samples stored in this Data Block, or as the number of
719 // samples in the curve, but where the last sample is not
720 // actually stored since it is always 0x3ff.
722 // The ATP Manager interprets this as the latter, so that's
723 // what we implement here.
724 for (unsigned j
= offset
+ 1; j
< offset
+ samples
; j
++) {
726 printf(" %.2f", sum
* 100.0 / 1023.0);
737 void edid_state::parse_displayid_display_intf(const unsigned char *x
)
739 check_displayid_datablock_revision(x
[1]);
741 if (!check_displayid_datablock_length(x
, 10, 10))
744 dispid
.has_display_interface_features
= true;
745 printf(" Interface Type: ");
748 switch (x
[3] & 0xf) {
749 case 0x00: printf("Analog 15HD/VGA\n"); break;
750 case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
751 case 0x02: printf("Analog VESA NAVI-D\n"); break;
752 default: printf("Reserved\n"); break;
755 case 0x01: printf("LVDS\n"); break;
756 case 0x02: printf("TMDS\n"); break;
757 case 0x03: printf("RSDS\n"); break;
758 case 0x04: printf("DVI-D\n"); break;
759 case 0x05: printf("DVI-I, analog\n"); break;
760 case 0x06: printf("DVI-I, digital\n"); break;
761 case 0x07: printf("HDMI-A\n"); break;
762 case 0x08: printf("HDMI-B\n"); break;
763 case 0x09: printf("MDDI\n"); break;
764 case 0x0a: printf("DisplayPort\n"); break;
765 case 0x0b: printf("Proprietary Digital Interface\n"); break;
766 default: printf("Reserved\n"); break;
769 printf(" Number of Links: %u\n", x
[3] & 0xf);
770 printf(" Interface Standard Version: %u.%u\n",
771 x
[4] >> 4, x
[4] & 0xf);
772 print_flags(" Supported bpc for RGB encoding", x
[5], bpc444
);
773 print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x
[6], bpc444
);
774 print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x
[7], bpc4xx
);
775 printf(" Supported Content Protection: ");
776 switch (x
[8] & 0xf) {
777 case 0x00: printf("None\n"); break;
778 case 0x01: printf("HDCP "); break;
779 case 0x02: printf("DTCP "); break;
780 case 0x03: printf("DPCP "); break;
781 default: printf("Reserved "); break;
784 printf("%u.%u\n", x
[9] >> 4, x
[9] & 0xf);
785 unsigned char v
= x
[0x0a] & 0xf;
786 printf(" Spread Spectrum: ");
787 switch (x
[0x0a] >> 6) {
788 case 0x00: printf("None\n"); break;
789 case 0x01: printf("Down Spread %.1f%%\n", v
/ 10.0); break;
790 case 0x02: printf("Center Spread %.1f%%\n", v
/ 10.0); break;
791 case 0x03: printf("Reserved\n"); break;
795 printf(" LVDS Color Mapping: %s mode\n",
796 (x
[0x0b] & 0x10) ? "6 bit compatible" : "normal");
797 if (x
[0x0b] & 0x08) printf(" LVDS supports 2.8V\n");
798 if (x
[0x0b] & 0x04) printf(" LVDS supports 12V\n");
799 if (x
[0x0b] & 0x02) printf(" LVDS supports 5V\n");
800 if (x
[0x0b] & 0x01) printf(" LVDS supports 3.3V\n");
801 printf(" LVDS %s Mode\n", (x
[0x0c] & 0x04) ? "Fixed" : "DE");
803 printf(" LVDS %s Signal Level\n", (x
[0x0c] & 0x02) ? "Low" : "High");
805 printf(" LVDS DE Polarity Active %s\n", (x
[0x0c] & 0x02) ? "Low" : "High");
806 printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x
[0x0c] & 0x01) ? "Rising" : "Falling");
809 printf(" PDI %s Mode\n", (x
[0x0b] & 0x04) ? "Fixed" : "DE");
811 printf(" PDI %s Signal Level\n", (x
[0x0b] & 0x02) ? "Low" : "High");
813 printf(" PDI DE Polarity Active %s\n", (x
[0x0b] & 0x02) ? "Low" : "High");
814 printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x
[0x0b] & 0x01) ? "Rising" : "Falling");
821 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x
)
823 check_displayid_datablock_revision(x
[1], 0xc0, 1);
826 case 0x00: printf(" Timings that explicitly report 3D capability\n"); break;
827 case 0x01: printf(" Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
828 case 0x02: printf(" All listed timings\n"); break;
829 case 0x03: printf(" Only Timings Codes listed here\n"); break;
836 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
837 (x
[5] & 1) ? "0/1" : "1/0");
840 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
841 (x
[5] & 1) ? "Right" : "Left");
844 printf(" Pixel Interleaved Stereo:\n");
845 for (unsigned y
= 0; y
< 8; y
++) {
846 unsigned char v
= x
[5 + y
];
849 for (int x
= 7; x
>= 0; x
--)
850 printf("%c", (v
& (1 << x
)) ? 'L' : 'R');
855 printf(" Dual Interface, Left and Right Separate\n");
856 printf(" Carries the %s-eye view\n",
857 (x
[5] & 1) ? "Right" : "Left");
859 switch ((x
[5] >> 1) & 3) {
860 case 0x00: printf("No mirroring\n"); break;
861 case 0x01: printf("Left/Right mirroring\n"); break;
862 case 0x02: printf("Top/Bottom mirroring\n"); break;
863 case 0x03: printf("Reserved\n"); break;
867 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
871 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
872 (x
[5] & 1) ? "Right" : "Left");
875 printf(" Proprietary\n");
878 printf(" Reserved\n");
881 if (!(x
[1] & 0x40)) // Has No Timing Codes
885 while (1U + (x
[0] & 0x1f) <= len
) {
886 unsigned num_codes
= x
[0] & 0x1f;
887 unsigned type
= x
[0] >> 6;
890 for (unsigned i
= 1; i
<= num_codes
; i
++) {
893 sprintf(type_name
, "DMT 0x%02x", x
[i
]);
894 print_timings(" ", find_dmt_id(x
[i
]), type_name
);
897 sprintf(type_name
, "VIC %3u", x
[i
]);
898 print_timings(" ", find_vic_id(x
[i
]), type_name
);
901 sprintf(type_name
, "HDMI VIC %u", x
[i
]);
902 print_timings(" ", find_hdmi_vic_id(x
[i
]), type_name
);
907 len
-= 1 + num_codes
;
914 void edid_state::parse_displayid_type_5_timing(const unsigned char *x
)
916 struct timings t
= {};
917 std::string
s("aspect ");
919 t
.hact
= 1 + (x
[2] | (x
[3] << 8));
920 t
.vact
= 1 + (x
[4] | (x
[5] << 8));
922 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
923 switch ((x
[0] >> 5) & 0x3) {
925 s
+= ", no 3D stereo";
931 s
+= ", 3D stereo depends on user action";
935 fail("Reserved stereo 0x03.\n");
939 s
+= ", refresh rate * (1000/1001) supported";
942 if ((x
[0] & 0x03) == 1)
943 warn("Unexpected use of 'custom reduced blanking'.\n");
944 else if ((x
[0] & 0x03) > 1)
945 fail("Invalid Timing Formula.\n");
947 edid_cvt_mode(1 + x
[6], t
);
951 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
954 print_timings(" ", &t
, "CVT", s
.c_str());
959 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x
, bool is_v2
)
961 check_displayid_datablock_revision(x
[1]);
963 if (!check_displayid_datablock_length(x
, 22, 22))
966 unsigned caps
= x
[3];
967 unsigned num_v_tile
= (x
[4] & 0xf) | (x
[6] & 0x30);
968 unsigned num_h_tile
= (x
[4] >> 4) | ((x
[6] >> 2) & 0x30);
969 unsigned tile_v_location
= (x
[5] & 0xf) | ((x
[6] & 0x3) << 4);
970 unsigned tile_h_location
= (x
[5] >> 4) | (((x
[6] >> 2) & 0x3) << 4);
971 unsigned tile_width
= x
[7] | (x
[8] << 8);
972 unsigned tile_height
= x
[9] | (x
[10] << 8);
973 unsigned pix_mult
= x
[11];
975 printf(" Capabilities:\n");
976 printf(" Behavior if it is the only tile: ");
977 switch (caps
& 0x07) {
978 case 0x00: printf("Undefined\n"); break;
979 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
980 case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
981 case 0x03: printf("Image is cloned to all other tiles\n"); break;
982 default: printf("Reserved\n"); break;
984 printf(" Behavior if more than one tile and fewer than total number of tiles: ");
985 switch ((caps
>> 3) & 0x03) {
986 case 0x00: printf("Undefined\n"); break;
987 case 0x01: printf("Image is displayed at the Tile Location\n"); break;
988 default: printf("Reserved\n"); break;
991 printf(" Tiled display consists of a single physical display enclosure\n");
993 printf(" Tiled display consists of multiple physical display enclosures\n");
994 printf(" Num horizontal tiles: %u Num vertical tiles: %u\n",
995 num_h_tile
+ 1, num_v_tile
+ 1);
996 printf(" Tile location: %u, %u\n", tile_h_location
, tile_v_location
);
997 printf(" Tile resolution: %ux%u\n", tile_width
+ 1, tile_height
+ 1);
1000 printf(" Top bevel size: %.1f pixels\n",
1001 pix_mult
* x
[12] / 10.0);
1002 printf(" Bottom bevel size: %.1f pixels\n",
1003 pix_mult
* x
[13] / 10.0);
1004 printf(" Right bevel size: %.1f pixels\n",
1005 pix_mult
* x
[14] / 10.0);
1006 printf(" Left bevel size: %.1f pixels\n",
1007 pix_mult
* x
[15] / 10.0);
1009 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1011 printf(" Tile resolution: %ux%u\n", tile_width
+ 1, tile_height
+ 1);
1012 } else if (pix_mult
) {
1013 fail("No bevel information, but the pixel multiplier is non-zero.\n");
1016 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1017 x
[0x10], x
[0x11], x
[0x12]);
1019 printf(" Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1020 x
[0x10], x
[0x11], x
[0x12]);
1021 printf(" Tiled Display Product ID Code: %u\n",
1022 x
[0x13] | (x
[0x14] << 8));
1023 if (hide_serial_numbers
)
1024 printf(" Tiled Display Serial Number: ...\n");
1026 printf(" Tiled Display Serial Number: %u\n",
1027 x
[0x15] | (x
[0x16] << 8) | (x
[0x17] << 16)| (x
[0x18] << 24));
1032 void edid_state::parse_displayid_type_6_timing(const unsigned char *x
)
1034 struct timings t
= {};
1035 std::string
s("aspect ");
1037 t
.pixclk_khz
= 1 + (x
[0] + (x
[1] << 8) + ((x
[2] & 0x3f) << 16));
1038 t
.hact
= 1 + (x
[3] | ((x
[4] & 0x3f) << 8));
1039 if ((x
[4] >> 7) & 0x1)
1040 t
.pos_pol_hsync
= true;
1041 unsigned hbl
= 1 + (x
[7] | ((x
[9] & 0xf) << 8));
1042 t
.hfp
= 1 + (x
[8] | ((x
[9] & 0xf0) << 4));
1043 t
.hsync
= 1 + x
[10];
1044 t
.hbp
= hbl
- t
.hfp
- t
.hsync
;
1045 t
.vact
= 1 + (x
[5] | ((x
[6] & 0x3f) << 8));
1046 if ((x
[6] >> 7) & 0x1)
1047 t
.pos_pol_vsync
= true;
1048 unsigned vbl
= 1 + x
[11];
1050 t
.vsync
= 1 + (x
[13] & 0x0f);
1051 t
.vbp
= vbl
- t
.vfp
- t
.vsync
;
1054 t
.interlaced
= true;
1060 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1062 double aspect_mult
= x
[14] * 3.0 / 256.0;
1063 unsigned size_mult
= 1 + (x
[16] >> 4);
1065 t
.vsize_mm
= size_mult
* (1 + (x
[15] | ((x
[16] & 0xf) << 8)));
1066 t
.hsize_mm
= t
.vsize_mm
* aspect_mult
;
1069 switch ((x
[13] >> 5) & 0x3) {
1071 s
+= ", no 3D stereo";
1077 s
+= ", 3D stereo depends on user action";
1081 fail("Reserved stereo 0x03.\n");
1087 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
1090 print_timings(" ", &t
, "DTD", s
.c_str(), true);
1093 static std::string
ieee7542d(unsigned short fp
)
1095 int exp
= ((fp
& 0x7c00) >> 10) - 15;
1096 unsigned fract
= (fp
& 0x3ff) | 0x400;
1099 return "do not use";
1102 return std::to_string(pow(2, exp
) * fract
/ 1024.0) + " cd/m^2";
1107 void edid_state::parse_displayid_parameters_v2(const unsigned char *x
,
1110 if (!check_displayid_datablock_length(x
, 29, 29))
1113 unsigned hor_size
= (x
[4] << 8) + x
[3];
1114 unsigned vert_size
= (x
[6] << 8) + x
[5];
1116 dispid
.has_display_parameters
= true;
1118 printf(" Image size: %u mm x %u mm\n",
1119 hor_size
, vert_size
);
1121 printf(" Image size: %.1f mm x %.1f mm\n",
1122 hor_size
/ 10.0, vert_size
/ 10.0);
1123 unsigned w
= (x
[8] << 8) + x
[7];
1124 unsigned h
= (x
[10] << 8) + x
[9];
1126 printf(" Native Format: %ux%u\n", w
, h
);
1127 dispid
.native_width
= w
;
1128 dispid
.native_height
= h
;
1129 } else if (w
|| h
) {
1130 fail("Invalid Native Format %ux%u.\n", w
, h
);
1132 unsigned char v
= x
[11];
1133 printf(" Scan Orientation: ");
1135 case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1136 case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1137 case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1138 case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1139 case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1140 case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1141 case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1142 case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1144 printf(" Luminance Information: ");
1145 switch ((v
>> 3) & 0x03) {
1146 case 0x00: printf("Minimum guaranteed value\n"); break;
1147 case 0x01: printf("Guidance for the Source device\n"); break;
1148 default: printf("Reserved\n"); break;
1150 printf(" Color Information: CIE %u\n",
1151 (v
& 0x40) ? 1976 : 1931);
1152 printf(" Audio Speaker Information: %sintegrated\n",
1153 (v
& 0x80) ? "not " : "");
1154 printf(" Native Color Chromaticity:\n");
1155 printf(" Primary #1: (%.6f, %.6f)\n",
1156 fp2d(x
[0x0c] | ((x
[0x0d] & 0x0f) << 8)),
1157 fp2d(((x
[0x0d] & 0xf0) >> 4) | (x
[0x0e] << 4)));
1158 printf(" Primary #2: (%.6f, %.6f)\n",
1159 fp2d(x
[0x0f] | ((x
[0x10] & 0x0f) << 8)),
1160 fp2d(((x
[0x10] & 0xf0) >> 4) | (x
[0x11] << 4)));
1161 printf(" Primary #3: (%.6f, %.6f)\n",
1162 fp2d(x
[0x12] | ((x
[0x13] & 0x0f) << 8)),
1163 fp2d(((x
[0x13] & 0xf0) >> 4) | (x
[0x14] << 4)));
1164 printf(" White Point: (%.6f, %.6f)\n",
1165 fp2d(x
[0x15] | ((x
[0x16] & 0x0f) << 8)),
1166 fp2d(((x
[0x16] & 0xf0) >> 4) | (x
[0x17] << 4)));
1167 printf(" Native Maximum Luminance (Full Coverage): %s\n",
1168 ieee7542d(x
[0x18] | (x
[0x19] << 8)).c_str());
1169 printf(" Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1170 ieee7542d(x
[0x1a] | (x
[0x1b] << 8)).c_str());
1171 printf(" Native Minimum Luminance: %s\n",
1172 ieee7542d(x
[0x1c] | (x
[0x1d] << 8)).c_str());
1173 printf(" Native Color Depth: ");
1174 if (!(x
[0x1e] & 0x07))
1175 printf("Not defined\n");
1176 else if (bpc444
[x
[0x1e] & 0x07])
1177 printf("%s bpc\n", bpc444
[x
[0x1e] & 0x07]);
1179 printf("Reserved\n");
1180 printf(" Display Device Technology: ");
1181 switch ((x
[0x1e] >> 4) & 0x07) {
1182 case 0x00: printf("Not Specified\n"); break;
1183 case 0x01: printf("Active Matrix LCD\n"); break;
1184 case 0x02: printf("Organic LED\n"); break;
1185 default: printf("Reserved\n"); break;
1188 printf(" Display Device Theme Preference: %s\n",
1189 (x
[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1190 if (x
[0x1f] != 0xff)
1191 printf(" Native Gamma EOTF: %.2f\n",
1192 (100 + x
[0x1f]) / 100.0);
1197 void edid_state::parse_displayid_type_9_timing(const unsigned char *x
)
1199 struct timings t
= {};
1200 std::string
s("aspect ");
1202 t
.hact
= 1 + (x
[1] | (x
[2] << 8));
1203 t
.vact
= 1 + (x
[3] | (x
[4] << 8));
1205 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1206 switch ((x
[0] >> 5) & 0x3) {
1208 s
+= ", no 3D stereo";
1214 s
+= ", 3D stereo depends on user action";
1218 fail("Reserved stereo 0x03.\n");
1222 s
+= ", refresh rate * (1000/1001) supported";
1224 switch (x
[0] & 0x07) {
1225 case 1: t
.rb
= RB_CVT_V1
; break;
1226 case 2: t
.rb
= RB_CVT_V2
; break;
1230 edid_cvt_mode(1 + x
[5], t
);
1232 print_timings(" ", &t
, "CVT", s
.c_str());
1237 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x
)
1239 check_displayid_datablock_revision(x
[1], 0, (x
[1] & 7) == 1);
1241 if (!check_displayid_datablock_length(x
, 9, 9))
1244 printf(" Minimum Pixel Clock: %u kHz\n",
1245 1 + (x
[3] | (x
[4] << 8) | (x
[5] << 16)));
1246 printf(" Maximum Pixel Clock: %u kHz\n",
1247 1 + (x
[6] | (x
[7] << 8) | (x
[8] << 16)));
1248 printf(" Minimum Vertical Refresh Rate: %u Hz\n", x
[9]);
1250 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10] + ((x
[11] & 3) << 8));
1252 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10]);
1253 printf(" Seamless Dynamic Video Timing Support: %s\n",
1254 (x
[11] & 0x80) ? "Yes" : "No");
1259 static const char *colorspace_eotf_combinations
[] = {
1266 "BT.2020/SMPTE ST 2084"
1269 static const char *colorspace_eotf_reserved
[] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
1271 static const char *colorspaces
[] = {
1282 static const char *eotfs
[] = {
1296 void edid_state::parse_displayid_interface_features(const unsigned char *x
)
1298 check_displayid_datablock_revision(x
[1]);
1300 if (!check_displayid_datablock_length(x
, 9))
1303 dispid
.has_display_interface_features
= true;
1304 unsigned len
= x
[2];
1305 if (len
> 0) print_flags(" Supported bpc for RGB encoding", x
[3], bpc444
);
1306 if (len
> 1) print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x
[4], bpc444
);
1307 if (len
> 2) print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x
[5], bpc4xx
);
1308 if (len
> 3) print_flags(" Supported bpc for YCbCr 4:2:0 encoding", x
[6], bpc4xx
);
1309 if (len
> 4 && x
[7])
1310 printf(" Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1312 if (len
> 5) print_flags(" Supported audio capability and features (kHz)",
1313 x
[8], audiorates
, true);
1314 if (len
> 6) print_flags(" Supported color space and EOTF standard combination 1",
1315 x
[9], colorspace_eotf_combinations
);
1316 if (len
> 7) print_flags(" Supported color space and EOTF standard combination 2",x
[10], colorspace_eotf_reserved
);
1320 if (len
> 8 && x
[11]) {
1321 printf(" Supported color space and EOTF additional combinations:");
1322 for (i
= 0; i
< x
[11]; i
++) {
1324 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x
[11]);
1326 } else if (i
+ 10 > len
) {
1327 printf("\n Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x
[11], len
- 9);
1331 const char *colorspace
= "Out of range";
1332 const char *eotf
= "Out of range";
1333 unsigned colorspace_index
= (x
[12 + i
] >> 4) & 0xf;
1334 unsigned eotf_index
= x
[12 + i
] & 0xf;
1336 if (colorspace_index
< sizeof(colorspaces
) / sizeof(colorspaces
[0]))
1337 colorspace
= colorspaces
[colorspace_index
];
1338 if (eotf_index
< sizeof(eotfs
) / sizeof(eotfs
[0]))
1339 eotf
= eotfs
[eotf_index
];
1343 if (!strcmp(colorspace
, eotf
))
1344 printf("%s", colorspace
);
1346 printf("%s/%s", colorspace
, eotf
);
1350 check_displayid_datablock_length(x
, 9 + i
, 9 + i
, 9 + i
);
1355 void edid_state::parse_displayid_ContainerID(const unsigned char *x
)
1357 check_displayid_datablock_revision(x
[1]);
1359 if (check_displayid_datablock_length(x
, 16, 16)) {
1361 printf(" Container ID: %s\n", containerid2s(x
).c_str());
1367 void edid_state::parse_displayid_adaptive_sync(const unsigned char *x
)
1369 check_displayid_datablock_revision(x
[1], 0x70);
1371 unsigned size
= 6 + ((x
[1] >> 4) & 0x7);
1372 unsigned len
= x
[2];
1373 unsigned descriptor
= 1;
1377 fail("DisplayID payload length %u is not a multiple of %u.\n", len
, size
);
1378 while (len
>= size
) {
1379 printf(" Descriptor #%u:\n", descriptor
++);
1381 printf(" %sNative Panel Range\n", (x
[0] & 1) ? "" : "Non-");
1382 unsigned v
= (x
[0] >> 2) & 3;
1384 case 0: printf(" Fixed Average V-Total\n"); break;
1385 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1387 printf(" Reserved %u\n", v
);
1388 fail("Use of reserved value %u.\n", v
);
1392 printf(" Supports Seamless Transition\n");
1394 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
1396 printf(" 'Max Single Frame Duration Decrease' field value without jitter impact\n");
1397 printf(" Max Duration Increase: %.2f ms\n", x
[1] / 4.0);
1398 printf(" Max Duration Decrease: %.2f ms\n", x
[5] / 4.0);
1399 printf(" Min Refresh Rate: %u Hz\n", x
[2]);
1400 printf(" Max Refresh Rate: %u Hz\n", 1 + x
[3] + (x
[4] & 3) * 256);
1409 void edid_state::parse_displayid_type_10_timing(const unsigned char *x
,
1410 unsigned sz
, bool is_cta
)
1412 struct timings t
= {};
1413 std::string
s("aspect ");
1415 t
.hact
= 1 + (x
[1] | (x
[2] << 8));
1416 t
.vact
= 1 + (x
[3] | (x
[4] << 8));
1418 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1420 switch ((x
[0] >> 5) & 0x3) {
1422 s
+= ", no 3D stereo";
1428 s
+= ", 3D stereo depends on user action";
1432 fail("Reserved stereo 0x03.\n");
1436 switch (x
[0] & 0x07) {
1437 case 1: t
.rb
= RB_CVT_V1
; break;
1438 case 2: t
.rb
= RB_CVT_V2
; break;
1439 case 3: t
.rb
= RB_CVT_V3
; break;
1444 unsigned rb_h_blank
= rb
== RB_CVT_V3
? 80 : 0;
1447 if (rb
== RB_CVT_V2
) {
1448 s
+= ", refresh rate * (1000/1001) supported";
1450 } else if (rb
== RB_CVT_V3
) {
1451 s
+= ", hblank is 160 pixels";
1455 fail("VR_HB must be 0.\n");
1459 s
+= ", YCbCr 4:2:0";
1461 unsigned refresh
= 1 + x
[5] + (sz
== 6 ? 0 : ((x
[6] & 3) << 8));
1462 double add_vert_time
= 0;
1464 if (sz
> 6 && rb
== RB_CVT_V3
) {
1465 unsigned delta_hblank
= (x
[6] >> 2) & 7;
1467 if (rb_h_blank
== 80)
1468 rb_h_blank
= 80 + 8 * delta_hblank
;
1469 else if (delta_hblank
<= 5)
1470 rb_h_blank
= 160 + 8 * delta_hblank
;
1472 rb_h_blank
= 160 - (delta_hblank
- 5) * 8;
1474 unsigned vblank_time_perc
= (x
[6] >> 5) & 7;
1476 add_vert_time
= (vblank_time_perc
* 10000.0) / refresh
;
1479 edid_cvt_mode(refresh
, t
, rb_h_blank
, add_vert_time
);
1481 print_timings(" ", &t
, "CVT", s
.c_str());
1483 timings_ext
te(t
, "CVT", s
);
1484 cta
.vec_vtdbs
.push_back(te
);
1488 // tag 0x7e, OUI 3A-02-92 (VESA)
1490 void edid_state::parse_displayid_vesa(const unsigned char *x
)
1492 check_displayid_datablock_revision(x
[1]);
1494 if (!check_displayid_datablock_length(x
, 5, 7))
1497 unsigned len
= x
[2];
1499 printf(" Data Structure Type: ");
1501 case 0: printf("eDP\n"); break;
1502 case 1: printf("DP\n"); break;
1503 default: printf("Reserved (%d)\n", x
[0] & 7); break;
1506 if ((x
[0] >> 3) & 15)
1507 warn("Reserved bits 6:3 (%d) are not 0.\n", (x
[0] >> 3) & 15);
1509 printf(" Default Colorspace and EOTF Handling: %s\n",
1510 (x
[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1512 printf(" Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1514 if ((x
[1] & 0xf) > 8)
1515 warn("Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel exceeds 8.\n");
1517 if ((x
[1] >> 4) & 1)
1518 warn("Reserved bit 4 is not 0.\n");
1520 printf(" Multi-SST Operation: ");
1521 switch ((x
[1] >> 5) & 3) {
1522 case 0: printf("Not Supported\n"); break;
1523 case 1: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1524 case 2: printf("Four Streams (number of links shall be 4)\n"); break;
1525 case 3: printf("Reserved\n"); warn("Invalid option for Multi-SST Operation.\n"); break;
1528 if ((x
[1] >> 7) & 1)
1529 warn("Reserved bit 7 is not 0.\n");
1532 double bpp
= (x
[2] & 0x3f) + (x
[3] & 0x0f) / 16.0;
1533 printf(" Pass through timing's target DSC bits per pixel: %.4f\n", bpp
);
1539 void edid_state::parse_displayid_cta_data_block(const unsigned char *x
)
1541 check_displayid_datablock_revision(x
[1]);
1543 unsigned len
= x
[2];
1547 fail("Length is > 248.\n");
1552 for (i
= 0; i
< len
; i
+= (x
[i
] & 0x1f) + 1) {
1553 cta_block(x
+ i
, dispid
.found_tags
);
1557 fail("Length is %u instead of %u.\n", len
, i
);
1562 std::string
edid_state::product_type(unsigned char x
, bool heading
)
1564 std::string headingstr
;
1566 if (dispid
.version
< 0x20) {
1567 headingstr
= "Display Product Type";
1568 if (heading
) return headingstr
;
1569 dispid
.is_display
= x
== 2 || x
== 3 || x
== 4 || x
== 6;
1571 case 0: return "Extension Section";
1572 case 1: return "Test Structure; test equipment only";
1573 case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1574 case 3: return "Standalone display device";
1575 case 4: return "Television receiver";
1576 case 5: return "Repeater/translator";
1577 case 6: return "DIRECT DRIVE monitor";
1581 headingstr
= "Display Product Primary Use Case";
1582 if (heading
) return headingstr
;
1583 dispid
.is_display
= x
>= 2 && x
<= 8;
1585 case 0: return "Same primary use case as the base section";
1586 case 1: return "Test Structure; test equipment only";
1587 case 2: return "None of the listed primary use cases; generic display";
1588 case 3: return "Television (TV) display";
1589 case 4: return "Desktop productivity display";
1590 case 5: return "Desktop gaming display";
1591 case 6: return "Presentation display";
1592 case 7: return "Head-mounted Virtual Reality (VR) display";
1593 case 8: return "Head-mounted Augmented Reality (AR) display";
1597 fail("Unknown %s 0x%02x.\n", headingstr
.c_str(), x
);
1598 return std::string("Unknown " + headingstr
+ " (") + utohex(x
) + ")";
1601 void edid_state::preparse_displayid_block(const unsigned char *x
)
1603 unsigned length
= x
[2];
1608 unsigned offset
= 5;
1610 dispid
.preparsed_displayid_blocks
++;
1611 while (length
> 0) {
1612 unsigned tag
= x
[offset
];
1613 unsigned len
= x
[offset
+ 2];
1617 dispid
.preparsed_color_ids
|= 1 << ((x
[offset
+ 1] >> 3) & 0x0f);
1620 dispid
.preparsed_xfer_ids
|= 1 << ((x
[offset
+ 1] >> 4) & 0x0f);
1629 if (length
< len
+ 3)
1640 unsigned edid_state::displayid_block(const unsigned version
, const unsigned char *x
, unsigned length
)
1643 unsigned tag
= x
[0];
1644 unsigned tag_version
= (tag
< 0x20) ? 1 : (tag
< 0x7f) ? 2 : (tag
< 0x80) ? 1 : 0;
1645 bool dooutputname
= true;
1646 unsigned len
= (length
< 3) ? 0 : x
[2];
1647 bool hasoui
= false;
1653 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1654 x
+ 3, len
, &ouinum
, true, true, true);
1655 dooutputname
= false;
1658 case 0x01: data_block
= "Display Parameters Data Block (" + utohex(tag
) + ")"; break;
1659 case 0x02: data_block
= "Color Characteristics Data Block"; break;
1660 case 0x03: data_block
= "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1661 case 0x04: data_block
= "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1662 case 0x05: data_block
= "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1663 case 0x06: data_block
= "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1664 case 0x07: data_block
= "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1665 case 0x08: data_block
= "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1666 case 0x09: data_block
= "Video Timing Range Data Block"; break;
1667 case 0x0a: data_block
= "Product Serial Number Data Block"; break;
1668 case 0x0b: data_block
= "GP ASCII String Data Block"; break;
1669 case 0x0c: data_block
= "Display Device Data Data Block"; break;
1670 case 0x0d: data_block
= "Interface Power Sequencing Data Block"; break;
1671 case 0x0e: data_block
= "Transfer Characteristics Data Block"; break;
1672 case 0x0f: data_block
= "Display Interface Data Block"; break;
1673 case 0x10: data_block
= "Stereo Display Interface Data Block (" + utohex(tag
) + ")"; break;
1674 case 0x11: data_block
= "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1675 case 0x12: data_block
= "Tiled Display Topology Data Block (" + utohex(tag
) + ")"; break;
1676 case 0x13: data_block
= "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1677 // 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1680 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1681 x
+ 3, len
, &ouinum
, false, false, false);
1682 dooutputname
= false;
1685 case 0x21: data_block
= "Display Parameters Data Block (" + utohex(tag
) + ")"; break;
1686 case 0x22: data_block
= "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1687 case 0x23: data_block
= "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1688 case 0x24: data_block
= "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1689 case 0x25: data_block
= "Dynamic Video Timing Range Limits Data Block"; break;
1690 case 0x26: data_block
= "Display Interface Features Data Block"; break;
1691 case 0x27: data_block
= "Stereo Display Interface Data Block (" + utohex(tag
) + ")"; break;
1692 case 0x28: data_block
= "Tiled Display Topology Data Block (" + utohex(tag
) + ")"; break;
1693 case 0x29: data_block
= "ContainerID Data Block"; break;
1694 case 0x2b: data_block
= "Adaptive Sync Data Block"; break;
1695 case 0x32: data_block
= "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1696 // 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1698 data_block_oui("Vendor-Specific Data Block (" + utohex(tag
) + ")",
1699 x
+ 3, len
, &ouinum
, false, false, true);
1700 dooutputname
= false;
1705 data_block_oui("Vendor-Specific Data Block (" + utohex(tag
) + ")",
1706 x
+ 3, len
, &ouinum
, false, true, false);
1707 dooutputname
= false;
1712 case 0x81: data_block
= "CTA-861 DisplayID Data Block"; break;
1713 // 0x82 .. 0xff RESERVED
1714 default: data_block
= "Unknown DisplayID Data Block (" + utohex(tag
) + ", length " + std::to_string(length
) + ")"; break;
1718 // Report a problem when the remaining bytes are not 0.
1719 data_block
.clear(); // Probably not a Data Block so clear this.
1720 if (tag
|| (length
> 1 && x
[1])) {
1721 printf(" Filler:\n");
1722 fail("Not enough bytes remain (%d) for a DisplayID data block and the DisplayID filler is non-0.\n", length
);
1723 hex_block(" ", x
, length
);
1728 if (length
< len
+ 3) {
1729 data_block
.clear(); // Probably not a Data Block so clear this.
1730 printf(" Filler:\n");
1731 fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len
+ 3, length
);
1732 hex_block(" ", x
, length
);
1737 // A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1738 data_block
.clear(); // Probably not a Product Identification Data Block so clear this.
1739 if (!memchk(x
, length
)) {
1740 printf(" Filler:\n");
1741 fail("Non-0 filler bytes in the DisplayID block.\n");
1742 hex_block(" ", x
, length
);
1747 if (dooutputname
&& data_block
.length())
1748 printf(" %s:\n", data_block
.c_str());
1750 if (version
>= 0x20 && tag_version
== 1)
1751 fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1752 version
>> 4, version
& 0xf);
1753 if (version
< 0x20 && tag_version
== 2)
1754 fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1755 version
>> 4, version
& 0xf);
1757 unsigned block_rev
= x
[1] & 0x07;
1760 case 0x00: parse_displayid_product_id(x
); break;
1761 case 0x01: parse_displayid_parameters(x
); break;
1762 case 0x02: parse_displayid_color_characteristics(x
); break;
1764 check_displayid_datablock_revision(x
[1], 0, block_rev
& 1);
1765 for (i
= 0; i
< len
/ 20; i
++)
1766 parse_displayid_type_1_7_timing(&x
[3 + (i
* 20)], false, block_rev
);
1769 check_displayid_datablock_revision(x
[1]);
1770 for (i
= 0; i
< len
/ 11; i
++)
1771 parse_displayid_type_2_timing(&x
[3 + (i
* 11)]);
1774 check_displayid_datablock_revision(x
[1], 0, block_rev
& 1);
1775 for (i
= 0; i
< len
/ 3; i
++)
1776 parse_displayid_type_3_timing(&x
[3 + (i
* 3)]);
1779 check_displayid_datablock_revision(x
[1], 0xc0, 1);
1780 for (i
= 0; i
< len
; i
++)
1781 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6, x
[3 + i
]);
1784 check_displayid_datablock_revision(x
[1]);
1785 for (i
= 0; i
< min(len
, 10) * 8; i
++)
1786 if (x
[3 + i
/ 8] & (1 << (i
% 8))) {
1788 sprintf(type
, "DMT 0x%02x", i
+ 1);
1789 print_timings(" ", find_dmt_id(i
+ 1), type
);
1793 check_displayid_datablock_revision(x
[1]);
1794 for (i
= 0; i
< min(len
, 8) * 8; i
++)
1795 if (x
[3 + i
/ 8] & (1 << (i
% 8))) {
1797 sprintf(type
, "VIC %3u", i
+ 1);
1798 print_timings(" ", find_vic_id(i
+ 1), type
);
1801 case 0x09: parse_displayid_video_timing_range_limits(x
); break;
1803 case 0x0b: parse_displayid_string(x
); break;
1804 case 0x0c: parse_displayid_display_device(x
); break;
1805 case 0x0d: parse_displayid_intf_power_sequencing(x
); break;
1806 case 0x0e: parse_displayid_transfer_characteristics(x
); break;
1807 case 0x0f: parse_displayid_display_intf(x
); break;
1808 case 0x10: parse_displayid_stereo_display_intf(x
); break;
1810 check_displayid_datablock_revision(x
[1]);
1811 for (i
= 0; i
< len
/ 7; i
++)
1812 parse_displayid_type_5_timing(&x
[3 + (i
* 7)]);
1814 case 0x12: parse_displayid_tiled_display_topology(x
, false); break;
1816 check_displayid_datablock_revision(x
[1]);
1817 for (i
= 0; i
< len
; i
+= (x
[3 + i
+ 2] & 0x40) ? 17 : 14)
1818 parse_displayid_type_6_timing(&x
[3 + i
]);
1820 case 0x20: parse_displayid_product_id(x
); break;
1823 check_displayid_datablock_revision(x
[1], 0x80, 1);
1825 check_displayid_datablock_revision(x
[1], 0x80, 0);
1826 parse_displayid_parameters_v2(x
, block_rev
);
1832 check_displayid_datablock_revision(x
[1], 0x08, 2);
1833 else if (block_rev
== 1)
1834 check_displayid_datablock_revision(x
[1], 0x08, 1);
1836 check_displayid_datablock_revision(x
[1]);
1837 sz
+= (x
[1] & 0x70) >> 4;
1838 if (block_rev
>= 1 && (x
[1] & 0x08))
1839 printf(" These timings support DSC pass-through\n");
1840 for (i
= 0; i
< len
/ sz
; i
++)
1841 parse_displayid_type_1_7_timing(&x
[3 + i
* sz
], true, block_rev
);
1846 check_displayid_datablock_revision(x
[1], 0xe8, 1);
1848 check_displayid_datablock_revision(x
[1], 0xc8);
1850 for (i
= 0; i
< len
/ 2; i
++)
1851 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
1853 (x
[4 + i
* 2] << 8));
1855 for (i
= 0; i
< len
; i
++)
1856 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
1861 check_displayid_datablock_revision(x
[1]);
1862 for (i
= 0; i
< len
/ 6; i
++)
1863 parse_displayid_type_9_timing(&x
[3 + i
* 6]);
1865 case 0x25: parse_displayid_dynamic_video_timings_range_limits(x
); break;
1866 case 0x26: parse_displayid_interface_features(x
); break;
1867 case 0x27: parse_displayid_stereo_display_intf(x
); break;
1868 case 0x28: parse_displayid_tiled_display_topology(x
, true); break;
1869 case 0x29: parse_displayid_ContainerID(x
); break;
1870 case 0x2b: parse_displayid_adaptive_sync(x
); break;
1872 unsigned sz
= 6 + ((x
[1] & 0x70) >> 4);
1874 check_displayid_datablock_revision(x
[1], 0x70);
1875 for (i
= 0; i
< len
/ sz
; i
++)
1876 parse_displayid_type_10_timing(&x
[3 + i
* sz
], sz
);
1879 case 0x7e|kOUI_VESA
: parse_displayid_vesa(x
); break;
1880 case 0x81: parse_displayid_cta_data_block(x
); break;
1881 default: hex_block(" ", x
+ 3 + (hasoui
? 3 : 0), (len
> (hasoui
? 3 : 0)) ? len
- (hasoui
? 3 : 0) : 0); break;
1884 if ((tag
== 0x00 || tag
== 0x20) &&
1885 (!dispid
.is_base_block
|| dispid
.block_number
> 0))
1886 fail("%s is required to be the first DisplayID Data Block.\n",
1887 data_block
.c_str());
1889 dispid
.block_number
++;
1893 void edid_state::parse_displayid_block(const unsigned char *x
)
1895 unsigned version
= x
[1];
1896 unsigned length
= x
[2];
1897 unsigned prod_type
= x
[3]; // future check: based on type, check for required data blocks
1898 unsigned ext_count
= x
[4];
1900 printf(" Version: %u.%u\n Extension Count: %u\n",
1901 version
>> 4, version
& 0xf, ext_count
);
1903 if (dispid
.is_base_block
) {
1904 dispid
.version
= version
;
1905 printf(" %s: %s\n", product_type(prod_type
, true).c_str(),
1906 product_type(prod_type
, false).c_str());
1908 fail("DisplayID Base Block has no product type.\n");
1909 if (ext_count
!= dispid
.preparsed_displayid_blocks
- 1)
1910 fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
1912 ext_count
> 1 ? "s" : "",
1913 dispid
.preparsed_displayid_blocks
- 1);
1916 fail("Product Type should be 0 in extension block.\n");
1918 fail("Extension Count should be 0 in extension block.\n");
1919 if (version
!= dispid
.version
)
1920 fail("Got version %u.%u, expected %u.%u.\n",
1921 version
>> 4, version
& 0xf,
1922 dispid
.version
>> 4, dispid
.version
& 0xf);
1926 fail("DisplayID length %d is greater than 121.\n", length
);
1931 for (const unsigned char *y
= x
+ 5; length
> 0; y
+= len
) {
1932 len
= displayid_block(version
, y
, length
);
1937 * DisplayID length field is number of following bytes
1938 * but checksum is calculated over the entire structure
1939 * (excluding DisplayID-in-EDID magic byte)
1942 do_checksum(" ", x
+ 1, x
[2] + 5);
1944 if (!memchk(x
+ 1 + x
[2] + 5, 0x7f - (1 + x
[2] + 5))) {
1945 data_block
= "Padding";
1946 fail("DisplayID padding contains non-zero bytes.\n");
1948 dispid
.is_base_block
= false;
1951 void edid_state::check_displayid_blocks()
1953 data_block
= "DisplayID";
1954 if (!dispid
.has_product_identification
)
1955 fail("Missing DisplayID Product Identification Data Block.\n");
1956 if (dispid
.is_display
&& !dispid
.has_display_parameters
)
1957 fail("Missing DisplayID Display Parameters Data Block.\n");
1958 if (dispid
.is_display
&& !dispid
.has_display_interface_features
)
1959 fail("Missing DisplayID Display Interface Features Data Block.\n");
1960 if (dispid
.is_display
&& !dispid
.has_type_1_7
)
1961 fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
1962 dispid
.version
>= 0x20 ? "VII" : "I");
1963 if (dispid
.preferred_timings
.empty())
1964 fail("DisplayID expects at least one preferred timing.\n");