edid-decode: add support for DisplayID data blocks 0x0d and 0x0f
Support Interface Power Sequencing and Display Interface.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Hans Verkuil
4 years ago
10 | 10 | |
11 | 11 | #include "edid-decode.h" |
12 | 12 | |
13 | static const char *bpc444[] = {"6", "8", "10", "12", "14", "16", NULL, NULL}; | |
14 | static const char *bpc4xx[] = {"8", "10", "12", "14", "16", NULL, NULL, NULL}; | |
15 | static const char *audiorates[] = {"32", "44.1", "48", NULL, NULL, NULL, NULL, NULL}; | |
16 | ||
13 | 17 | // misc functions |
18 | ||
19 | static void print_flags(const char *label, unsigned char flag_byte, | |
20 | const char **flags, bool reverse = false) | |
21 | { | |
22 | if (!flag_byte) | |
23 | return; | |
24 | ||
25 | unsigned countflags = 0; | |
26 | ||
27 | printf("%s: ", label); | |
28 | for (unsigned i = 0; i < 8; i++) { | |
29 | if (flag_byte & (1 << (reverse ? 7 - i : i))) { | |
30 | if (countflags) | |
31 | printf(", "); | |
32 | if (flags[i]) | |
33 | printf("%s", flags[i]); | |
34 | else | |
35 | printf("Undefined (%u)", i); | |
36 | countflags++; | |
37 | } | |
38 | } | |
39 | printf("\n"); | |
40 | } | |
14 | 41 | |
15 | 42 | static void check_displayid_datablock_revision(const unsigned char *x) |
16 | 43 | { |
535 | 562 | v = x[0x0f]; |
536 | 563 | printf(" Response time for %s transition: %u ms\n", |
537 | 564 | (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f); |
565 | } | |
566 | ||
567 | // tag 0x0d | |
568 | ||
569 | static void parse_displayid_intf_power_sequencing(const unsigned char *x) | |
570 | { | |
571 | check_displayid_datablock_revision(x); | |
572 | ||
573 | if (!check_displayid_datablock_length(x, 6, 6)) | |
574 | return; | |
575 | ||
576 | printf(" Power Sequence T1: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2); | |
577 | printf(" Power Sequence T2: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2); | |
578 | printf(" Power Sequence T3: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2); | |
579 | printf(" Power Sequence T4: 0.0-%u.0 ms\n", (x[6] & 0x7f) * 10); | |
580 | printf(" Power Sequence T5: 0.0-%u.0 ms\n", (x[7] & 0x3f) * 10); | |
581 | printf(" Power Sequence T6: 0.0-%u.0 ms\n", (x[8] & 0x3f) * 10); | |
538 | 582 | } |
539 | 583 | |
540 | 584 | // tag 0x0e |
579 | 623 | } |
580 | 624 | offset += samples; |
581 | 625 | len -= samples; |
626 | } | |
627 | } | |
628 | ||
629 | // tag 0x0f | |
630 | ||
631 | static void parse_displayid_display_intf(const unsigned char *x) | |
632 | { | |
633 | check_displayid_datablock_revision(x); | |
634 | ||
635 | if (!check_displayid_datablock_length(x, 10, 10)) | |
636 | return; | |
637 | ||
638 | printf(" Interface Type: "); | |
639 | switch (x[3] >> 4) { | |
640 | case 0x00: | |
641 | switch (x[3] & 0xf) { | |
642 | case 0x00: printf("Analog 15HD/VGA\n"); break; | |
643 | case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break; | |
644 | case 0x02: printf("Analog VESA NAVI-D\n"); break; | |
645 | default: printf("Reserved\n"); break; | |
646 | } | |
647 | break; | |
648 | case 0x01: printf("LVDS\n"); break; | |
649 | case 0x02: printf("TMDS\n"); break; | |
650 | case 0x03: printf("RSDS\n"); break; | |
651 | case 0x04: printf("DVI-D\n"); break; | |
652 | case 0x05: printf("DVI-I, analog\n"); break; | |
653 | case 0x06: printf("DVI-I, digital\n"); break; | |
654 | case 0x07: printf("HDMI-A\n"); break; | |
655 | case 0x08: printf("HDMI-B\n"); break; | |
656 | case 0x09: printf("MDDI\n"); break; | |
657 | case 0x0a: printf("DisplayPort\n"); break; | |
658 | case 0x0b: printf("Proprietary Digital Interface\n"); break; | |
659 | default: printf("Reserved\n"); break; | |
660 | } | |
661 | if (x[3] >> 4) | |
662 | printf(" Number of Links: %u\n", x[3] & 0xf); | |
663 | printf(" Interface Standard Version: %u.%u\n", | |
664 | x[4] >> 4, x[4] & 0xf); | |
665 | print_flags(" Supported bpc for RGB encoding", x[5], bpc444); | |
666 | print_flags(" Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444); | |
667 | print_flags(" Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx); | |
668 | printf(" Supported Content Protection: "); | |
669 | switch (x[8] & 0xf) { | |
670 | case 0x00: printf("None\n"); break; | |
671 | case 0x01: printf("HDCP "); break; | |
672 | case 0x02: printf("DTCP "); break; | |
673 | case 0x03: printf("DPCP "); break; | |
674 | default: printf("Reserved "); break; | |
675 | } | |
676 | if (x[8] & 0xf) | |
677 | printf("%u.%u\n", x[9] >> 4, x[9] & 0xf); | |
678 | unsigned char v = x[0x0a] & 0xf; | |
679 | printf(" Spread Spectrum: "); | |
680 | switch (x[0x0a] >> 6) { | |
681 | case 0x00: printf("None\n"); break; | |
682 | case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break; | |
683 | case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break; | |
684 | case 0x03: printf("Reserved\n"); break; | |
685 | } | |
686 | switch (x[3] >> 4) { | |
687 | case 0x01: | |
688 | printf(" LVDS Color Mapping: %s mode\n", | |
689 | (x[0x0b] & 0x10) ? "6 bit compatible" : "normal"); | |
690 | if (x[0x0b] & 0x08) printf(" LVDS supports 2.8V\n"); | |
691 | if (x[0x0b] & 0x04) printf(" LVDS supports 12V\n"); | |
692 | if (x[0x0b] & 0x02) printf(" LVDS supports 5V\n"); | |
693 | if (x[0x0b] & 0x01) printf(" LVDS supports 3.3V\n"); | |
694 | printf(" LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE"); | |
695 | if (x[0x0c] & 0x04) | |
696 | printf(" LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High"); | |
697 | else | |
698 | printf(" LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High"); | |
699 | printf(" LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling"); | |
700 | break; | |
701 | case 0x0b: | |
702 | printf(" PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE"); | |
703 | if (x[0x0b] & 0x04) | |
704 | printf(" PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High"); | |
705 | else | |
706 | printf(" PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High"); | |
707 | printf(" PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling"); | |
708 | break; | |
582 | 709 | } |
583 | 710 | } |
584 | 711 | |
769 | 896 | |
770 | 897 | // tag 0x26 |
771 | 898 | |
772 | static const char *bpc444[] = {"6", "8", "10", "12", "14", "16", NULL, NULL}; | |
773 | static const char *bpc4xx[] = {"8", "10", "12", "14", "16", NULL, NULL, NULL}; | |
774 | static const char *audiorates[] = {"32", "44.1", "48", NULL, NULL, NULL, NULL, NULL}; | |
775 | ||
776 | 899 | static const char *colorspace_eotf_combinations[] = { |
777 | 900 | "sRGB", |
778 | 901 | "BT.601", |
809 | 932 | "Hybrid Log", |
810 | 933 | "Custom" |
811 | 934 | }; |
812 | ||
813 | static void print_flags(const char *label, unsigned char flag_byte, | |
814 | const char **flags, bool reverse = false) | |
815 | { | |
816 | if (!flag_byte) | |
817 | return; | |
818 | ||
819 | unsigned countflags = 0; | |
820 | ||
821 | printf("%s: ", label); | |
822 | for (unsigned i = 0; i < 8; i++) { | |
823 | if (flag_byte & (1 << (reverse ? 7 - i : i))) { | |
824 | if (countflags) | |
825 | printf(", "); | |
826 | if (flags[i]) | |
827 | printf("%s", flags[i]); | |
828 | else | |
829 | printf("Undefined (%u)", i); | |
830 | countflags++; | |
831 | } | |
832 | } | |
833 | printf("\n"); | |
834 | } | |
835 | 935 | |
836 | 936 | static void parse_displayid_interface_features(const unsigned char *x) |
837 | 937 | { |
1116 | 1216 | case 0x0a: |
1117 | 1217 | case 0x0b: parse_displayid_string(x + offset); break; |
1118 | 1218 | case 0x0c: parse_displayid_display_device(x + offset); break; |
1219 | case 0x0d: parse_displayid_intf_power_sequencing(x + offset); break; | |
1119 | 1220 | case 0x0e: parse_displayid_transfer_characteristics(x + offset); break; |
1221 | case 0x0f: parse_displayid_display_intf(x + offset); break; | |
1120 | 1222 | case 0x11: |
1121 | 1223 | for (i = 0; i < len / 7; i++) |
1122 | 1224 | parse_displayid_type_5_timing(&x[offset + 3 + (i * 7)]); |