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::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
);
146 fail("Invalid Native Pixel Format %ux%u.\n", w
, h
);
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))
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
);
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);
188 static const char *std_colorspace_ids
[] = {
196 "Adobe Wide Gamut RGB",
200 static double fp2d(unsigned short fp
)
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;
216 printf(" Uses %s color\n", temporal_color
? "temporal" : "spatial");
217 printf(" Uses %u CIE (x, y) coordinates\n", cie_year
);
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]]);
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)));
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
= {};
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) {
261 t
.hratio
= t
.vratio
= 1;
303 fail("Unknown aspect 0x%02x.\n", x
[3] & 0xf);
306 switch ((x
[3] >> 5) & 0x3) {
308 s
+= ", no 3D stereo";
312 dispid
.has_stereo
= true;
315 s
+= ", 3D stereo depends on user action";
316 dispid
.has_stereo
= true;
320 fail("Reserved stereo 0x03.\n");
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;
349 if (block_rev
< 2 && (x
[3] & 0x80)) {
351 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
354 print_timings(" ", &t
, name
.c_str(), s
.c_str(), true);
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
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");
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");
377 timings cvt_t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, RB_CVT_V3
,
379 if (match_timings(t
, cvt_t
))
380 fail("This T7VTDB can be represented as a T10VTDB.\n");
386 void edid_state::parse_displayid_type_2_timing(const unsigned char *x
)
388 struct timings t
= {};
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));
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;
417 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
419 switch ((x
[3] >> 5) & 0x3) {
421 s
+= ", no 3D stereo";
425 dispid
.has_stereo
= true;
428 s
+= ", 3D stereo depends on user action";
429 dispid
.has_stereo
= true;
433 fail("Reserved stereo 0x03.\n");
438 dispid
.preferred_timings
.push_back(timings_ext(t
, "DTD", s
));
441 print_timings(" ", &t
, "DTD", s
.c_str(), true);
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) {
454 t
.hratio
= t
.vratio
= 1;
496 fail("Unknown aspect 0x%02x.\n", x
[0] & 0xf);
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
);
508 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
511 print_timings(" ", &t
, "CVT", s
.c_str());
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
;
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;
528 print_timings(" ", t
, type_name
);
529 if (t
&& is_cta
&& !cta
.t8vtdb
.is_valid()) {
530 timings_ext
te(*t
, type_name
, "");
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))
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));
551 printf(" Supports Interlaced\n");
553 printf(" Supports CVT\n");
555 printf(" Supports CVT Reduced Blanking\n");
557 printf(" Discrete frequency display device\n");
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]));
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))
578 printf(" Display Device Technology: ");
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: ");
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;
626 printf(" The backlight may be switched on and off\n");
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);
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: ");
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");
670 printf(" Sub-pixel layout/configuration/shape: ");
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);
691 printf(" Response time for %s transition: %u ms\n",
692 (v
& 0x80) ? "white-to-black" : "black-to-white", v
& 0x7f);
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))
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);
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;
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
);
728 printf(" The first curve is the 'white' transfer characteristic\n");
730 printf(" Individual response curves\n");
733 unsigned len
= x
[2] - 1;
735 for (unsigned i
= 0; len
; i
++) {
736 if ((x
[3] & 0x80) && !i
)
737 printf(" White curve: ");
739 printf(" Response curve #%u:",
741 unsigned samples
= x
[offset
];
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);
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
++) {
762 printf(" %.2f", sum
* 100.0 / 1023.0);
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))
780 dispid
.has_display_interface_features
= true;
781 printf(" Interface Type: ");
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;
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;
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;
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;
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");
839 printf(" LVDS %s Signal Level\n", (x
[0x0c] & 0x02) ? "Low" : "High");
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");
845 printf(" PDI %s Mode\n", (x
[0x0b] & 0x04) ? "Fixed" : "DE");
847 printf(" PDI %s Signal Level\n", (x
[0x0b] & 0x02) ? "Low" : "High");
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");
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);
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;
874 printf(" Field Sequential Stereo (L/R Polarity: %s)\n",
875 (x
[5] & 1) ? "0/1" : "1/0");
878 printf(" Side-by-side Stereo (Left Half = %s Eye View)\n",
879 (x
[5] & 1) ? "Right" : "Left");
882 printf(" Pixel Interleaved Stereo:\n");
883 for (unsigned y
= 0; y
< 8; y
++) {
884 unsigned char v
= x
[5 + y
];
887 for (int x
= 7; x
>= 0; x
--)
888 printf("%c", (v
& (1 << x
)) ? 'L' : 'R');
893 printf(" Dual Interface, Left and Right Separate\n");
894 printf(" Carries the %s-eye view\n",
895 (x
[5] & 1) ? "Right" : "Left");
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;
905 printf(" Multi-View: %u views, Interleaving Method Code: %u\n",
909 printf(" Stacked Frame Stereo (Top Half = %s Eye View)\n",
910 (x
[5] & 1) ? "Right" : "Left");
913 printf(" Proprietary\n");
916 printf(" Reserved\n");
919 if (!(x
[1] & 0x40)) // Has No Timing Codes
923 while (1U + (x
[0] & 0x1f) <= len
) {
924 unsigned num_codes
= x
[0] & 0x1f;
925 unsigned type
= x
[0] >> 6;
928 for (unsigned i
= 1; i
<= num_codes
; i
++) {
931 sprintf(type_name
, "DMT 0x%02x", x
[i
]);
932 print_timings(" ", find_dmt_id(x
[i
]), type_name
);
935 sprintf(type_name
, "VIC %3u", x
[i
]);
936 print_timings(" ", find_vic_id(x
[i
]), type_name
);
939 sprintf(type_name
, "HDMI VIC %u", x
[i
]);
940 print_timings(" ", find_hdmi_vic_id(x
[i
]), type_name
);
945 len
-= 1 + num_codes
;
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));
960 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
961 switch ((x
[0] >> 5) & 0x3) {
963 s
+= ", no 3D stereo";
967 dispid
.has_stereo
= true;
970 s
+= ", 3D stereo depends on user action";
971 dispid
.has_stereo
= true;
975 fail("Reserved stereo 0x03.\n");
979 s
+= ", refresh rate * (1000/1001) supported";
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
);
991 dispid
.preferred_timings
.push_back(timings_ext(t
, "CVT", s
));
994 print_timings(" ", &t
, "CVT", s
.c_str());
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))
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;
1033 printf(" Tiled display consists of a single physical display enclosure\n");
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);
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);
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");
1058 printf(" Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1059 x
[0x10], x
[0x11], x
[0x12]);
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);
1067 if (hide_serial_numbers
)
1068 printf(" Tiled Display Serial Number: ...\n");
1070 printf(" Tiled Display Serial Number: %u\n", sn
);
1072 fail("Tiled Display Serial Number must be non-zero.\n");
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];
1096 t
.vsync
= 1 + (x
[13] & 0x0f);
1097 t
.vbp
= vbl
- t
.vfp
- t
.vsync
;
1100 t
.interlaced
= true;
1106 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
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) {
1117 s
+= ", no 3D stereo";
1121 dispid
.has_stereo
= true;
1124 s
+= ", 3D stereo depends on user action";
1125 dispid
.has_stereo
= true;
1129 fail("Reserved stereo 0x03.\n");
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;
1147 return "do not use";
1150 return std::to_string(pow(2, exp
) * fract
/ 1024.0) + " cd/m^2";
1155 void edid_state::parse_displayid_parameters_v2(const unsigned char *x
,
1158 check_displayid_datablock_revision(x
[1], 0, (x
[1] & 7) == 1);
1159 if (!check_displayid_datablock_length(x
, 29, 29))
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
;
1171 printf(" Image size: %u mm x %u mm\n", hor_size
, vert_size
);
1172 dispid
.image_width
*= 10;
1173 dispid
.image_height
*= 10;
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: ");
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]);
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;
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);
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));
1263 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1264 switch ((x
[0] >> 5) & 0x3) {
1266 s
+= ", no 3D stereo";
1270 dispid
.has_stereo
= true;
1273 s
+= ", 3D stereo depends on user action";
1274 dispid
.has_stereo
= true;
1278 fail("Reserved stereo 0x03.\n");
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;
1290 edid_cvt_mode(1 + x
[5], t
);
1292 print_timings(" ", &t
, "CVT", s
.c_str());
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))
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]);
1310 printf(" Maximum Vertical Refresh Rate: %u Hz\n", x
[10] + ((x
[11] & 3) << 8));
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");
1319 static const char *colorspace_eotf_combinations
[] = {
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
[] = {
1342 static const char *eotfs
[] = {
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))
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",
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
);
1380 if (len
> 8 && x
[11]) {
1381 printf(" Supported color space and EOTF additional combinations:");
1382 for (i
= 0; i
< x
[11]; i
++) {
1384 printf("\n Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x
[11]);
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);
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
];
1403 if (!strcmp(colorspace
, eotf
))
1404 printf("%s", colorspace
);
1406 printf("%s/%s", colorspace
, eotf
);
1410 check_displayid_datablock_length(x
, 9 + i
, 9 + i
, 9 + i
);
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)) {
1421 printf(" Container ID: %s\n", containerid2s(x
).c_str());
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;
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;
1444 case 0: printf(" Fixed Average V-Total\n"); break;
1445 case 1: printf(" Fixed Average V-Total and Adaptive V-Total\n"); break;
1447 printf(" Reserved %u\n", v
);
1448 fail("Use of reserved value %u.\n", v
);
1452 printf(" Supports Seamless Transition\n");
1454 printf(" 'Max Single Frame Duration Increase' field value without jitter impact\n");
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);
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))
1481 // TODO: parse the DB
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))
1498 // TODO: parse the DB
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))
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
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));
1534 s
+= std::to_string(t
.hratio
) + ":" + std::to_string(t
.vratio
);
1536 switch ((x
[0] >> 5) & 0x3) {
1538 s
+= ", no 3D stereo";
1542 dispid
.has_stereo
= true;
1545 s
+= ", 3D stereo depends on user action";
1546 dispid
.has_stereo
= true;
1550 fail("Reserved stereo 0x03.\n");
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;
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;
1569 if (rb
== RB_CVT_V2
) {
1570 s
+= ", refresh rate * (1000/1001) supported";
1572 } else if (rb
== RB_CVT_V3
) {
1573 s
+= ", hblank is 160 pixels";
1577 fail("VR_HB must be 0.\n");
1581 s
+= ", YCbCr 4:2:0";
1582 dispid
.has_ycbcr_420
= true;
1586 if (rb
== RB_CVT_V3
) {
1587 early_vsync_rqd
= true;
1588 s
+= ", early-vsync";
1590 fail("EVS must be 0.\n");
1594 unsigned refresh
= 1 + x
[5] + (sz
== 6 ? 0 : ((x
[6] & 3) << 8));
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
;
1605 rb_h_blank
= 160 - (delta_hblank
- 5) * 8;
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
);
1614 fail("Additional_Vertical_Blank_Time must be 0.\n");
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());
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))
1638 unsigned len
= x
[2];
1640 printf(" Data Structure Type: ");
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",
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");
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;
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
1690 printf(" Type: BLC Info/Corrections, Version: %u\n", x
[1]);
1693 printf(" Type: %u, Version: %u\n", x
[0], x
[1]);
1696 hex_block(" ", x
+ 2, length
- 2);
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];
1709 fail("Length is > 248.\n");
1714 for (i
= 0; i
< len
; i
+= (x
[i
] & 0x1f) + 1) {
1715 cta_block(x
+ i
, dispid
.found_tags
);
1719 fail("Length is %u instead of %u.\n", len
, i
);
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;
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";
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;
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";
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;
1773 dispid
.preparsed_displayid_blocks
++;
1774 while (length
> 0) {
1775 unsigned tag
= x
[offset
];
1776 unsigned len
= x
[offset
+ 2];
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;
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;
1811 if (replace_unique_ids
) {
1812 update_checksum
= true;
1813 memset(x
+ offset
+ 3, 0, 16);
1817 dispid
.preparsed_color_ids
|= 1 << ((x
[offset
+ 1] >> 3) & 0x0f);
1820 dispid
.preparsed_xfer_ids
|= 1 << ((x
[offset
+ 1] >> 4) & 0x0f);
1829 if (length
< 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
)
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;
1857 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1858 x
+ 3, len
, &ouinum
, true, true, true);
1859 dooutputname
= false;
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
1884 data_block_oui("Product Identification Data Block (" + utohex(tag
) + ")",
1885 x
+ 3, len
, &ouinum
, false, false, true);
1886 dooutputname
= false;
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;
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;
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;
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
);
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
);
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
);
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;
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;
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
);
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)]);
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)]);
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
]);
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))) {
1995 sprintf(type
, "DMT 0x%02x", i
+ 1);
1996 print_timings(" ", find_dmt_id(i
+ 1), type
);
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))) {
2004 sprintf(type
, "VIC %3u", i
+ 1);
2005 print_timings(" ", find_vic_id(i
+ 1), type
);
2008 case 0x09: parse_displayid_video_timing_range_limits(x
); break;
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;
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)]);
2021 case 0x12: parse_displayid_tiled_display_topology(x
, false); break;
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
]);
2027 case 0x20: parse_displayid_product_id(x
); break;
2030 check_displayid_datablock_revision(x
[1], 0x80, 1);
2032 check_displayid_datablock_revision(x
[1], 0x80, 0);
2033 parse_displayid_parameters_v2(x
, block_rev
);
2039 check_displayid_datablock_revision(x
[1], 0x08, 2);
2040 else if (block_rev
== 1)
2041 check_displayid_datablock_revision(x
[1], 0x08, 1);
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
);
2053 check_displayid_datablock_revision(x
[1], 0xe8, 1);
2055 check_displayid_datablock_revision(x
[1], 0xc8);
2057 for (i
= 0; i
< len
/ 2; i
++)
2058 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
2060 (x
[4 + i
* 2] << 8));
2062 for (i
= 0; i
< len
; i
++)
2063 parse_displayid_type_4_8_timing((x
[1] & 0xc0) >> 6,
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]);
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;
2082 unsigned sz
= 6 + ((x
[1] & 0x70) >> 4);
2084 check_displayid_datablock_revision(x
[1], 0x70);
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
);
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
++;
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());
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",
2126 ext_count
> 1 ? "s" : "",
2127 dispid
.preparsed_displayid_blocks
- 1);
2130 fail("Product Type should be 0 in extension block.\n");
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);
2140 fail("DisplayID length %d is greater than 121.\n", length
);
2145 for (const unsigned char *y
= x
+ 5; length
> 0; y
+= len
) {
2146 len
= displayid_block(version
, y
, length
);
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)
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
);