aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2020-11-18 11:53:34 +0100
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2020-12-30 11:34:26 +0100
commit046bb92ce0ef1c797068d211dea38e1f92500068 (patch)
tree4186e5db5fb58af5fdbf062b27f1ec28d7824485
parentf70db9e3aabcf307c8b0f328a6d3221a1c276d80 (diff)
edid-decode: parse new CTA DisplayID Data Blocks
Add support for DisplayID Types VII, VIII and X to the CTA parser. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--edid-decode.cpp2
-rw-r--r--edid-decode.h9
-rw-r--r--parse-cta-block.cpp63
-rw-r--r--parse-displayid-block.cpp100
4 files changed, 158 insertions, 16 deletions
diff --git a/edid-decode.cpp b/edid-decode.cpp
index 8f42b2f..f6da158 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -418,6 +418,8 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
s = "RB";
if (t->rb == 2)
s += "v2";
+ else if (t->rb == 3)
+ s += "v3";
}
add_str(s, flags);
if (t->hsize_mm || t->vsize_mm)
diff --git a/edid-decode.h b/edid-decode.h
index e8c464e..030bb07 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -259,6 +259,9 @@ struct edid_state {
void cta_y420cmdb(const unsigned char *x, unsigned length);
void cta_vfpdb(const unsigned char *x, unsigned length);
void cta_hdmi_block(const unsigned char *x, unsigned length);
+ void cta_displayid_type_7(const unsigned char *x, unsigned length);
+ void cta_displayid_type_8(const unsigned char *x, unsigned length);
+ void cta_displayid_type_10(const unsigned char *x, unsigned length);
void cta_ext_block(const unsigned char *x, unsigned length);
void cta_block(const unsigned char *x);
void preparse_cta_block(const unsigned char *x);
@@ -285,10 +288,11 @@ struct edid_state {
void parse_displayid_color_characteristics(const unsigned char *x);
void parse_displayid_transfer_characteristics(const unsigned char *x);
void parse_displayid_stereo_display_intf(const unsigned char *x);
- void parse_displayid_type_1_7_timing(const unsigned char *x, bool type7);
+ void parse_displayid_type_1_7_timing(const unsigned char *x,
+ bool type7, unsigned block_rev, bool is_cta = false);
void parse_displayid_type_2_timing(const unsigned char *x);
void parse_displayid_type_3_timing(const unsigned char *x);
- void parse_displayid_type_4_8_timing(unsigned char type, unsigned short id);
+ void parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta = false);
void parse_displayid_video_timing_range_limits(const unsigned char *x);
void parse_displayid_string(const unsigned char *x);
void parse_displayid_display_device(const unsigned char *x);
@@ -299,6 +303,7 @@ struct edid_state {
void parse_displayid_type_9_timing(const unsigned char *x);
void parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x);
void parse_displayid_ContainerID(const unsigned char *x);
+ void parse_displayid_type_10_timing(const unsigned char *x, bool is_cta = false);
void preparse_displayid_block(const unsigned char *x);
void parse_displayid_block(const unsigned char *x);
void parse_displayid_vesa(const unsigned char *x);
diff --git a/parse-cta-block.cpp b/parse-cta-block.cpp
index 98ec2ee..7a2ff8a 100644
--- a/parse-cta-block.cpp
+++ b/parse-cta-block.cpp
@@ -1616,6 +1616,62 @@ static void cta_ifdb(const unsigned char *x, unsigned length)
}
}
+void edid_state::cta_displayid_type_7(const unsigned char *x, unsigned length)
+{
+ check_displayid_datablock_revision(x[0], 0x00, 2);
+
+ if (length < 21U + ((x[0] & 0x70) >> 4)) {
+ fail("Empty Data Block with length %u.\n", length);
+ return;
+ }
+ parse_displayid_type_1_7_timing(x + 1, true, 2, true);
+}
+
+void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
+{
+ check_displayid_datablock_revision(x[0], 0xe8, 1);
+ if (length < ((x[0] & 0x08) ? 3 : 2)) {
+ fail("Empty Data Block with length %u.\n", length);
+ return;
+ }
+
+ unsigned sz = (x[0] & 0x08) ? 2 : 1;
+ unsigned type = x[0] >> 6;
+
+ if (type) {
+ fail("Only code type 0 is supported.\n");
+ return;
+ }
+
+ if (x[0] & 0x20)
+ printf(" Also supports YCbCr 4:2:0\n");
+
+ x++;
+ length--;
+ for (unsigned i = 0; i < length / sz; i++) {
+ unsigned id = x[i * sz];
+
+ if (sz == 2)
+ id |= x[i * sz + 1] << 8;
+ parse_displayid_type_4_8_timing(type, id, true);
+ }
+}
+
+void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
+{
+ check_displayid_datablock_revision(x[0], 0x70);
+ if (length < 7U + ((x[0] & 0x70) >> 4)) {
+ fail("Empty Data Block with length %u.\n", length);
+ return;
+ }
+
+ unsigned sz = 6U + ((x[0] & 0x70) >> 4);
+ x++;
+ length--;
+ for (unsigned i = 0; i < length / sz; i++)
+ parse_displayid_type_10_timing(x + i * sz, true);
+}
+
static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
{
unsigned num_descs;
@@ -1710,6 +1766,10 @@ void edid_state::cta_ext_block(const unsigned char *x, unsigned length)
case 0x20: data_block = "InfoFrame Data Block"; break;
+ case 0x34: data_block = "DisplayID Type VII Video Timing Data Block"; break;
+ case 0x35: data_block = "DisplayID Type VIII Video Timing Data Block"; break;
+ case 0x42: data_block = "DisplayID Type X Video Timing Data Block"; break;
+
case 0x78: data_block = "HDMI Forum EDID Extension Override Data Block"; break;
case 0x79: data_block = "HDMI Forum Sink Capability Data Block"; break;
default:
@@ -1812,6 +1872,9 @@ void edid_state::cta_ext_block(const unsigned char *x, unsigned length)
case 0x13: cta_rcdb(x + 1, length); return;
case 0x14: cta_sldb(x + 1, length); return;
case 0x20: cta_ifdb(x + 1, length); return;
+ case 0x34: cta_displayid_type_7(x + 1, length); return;
+ case 0x35: cta_displayid_type_8(x + 1, length); return;
+ case 0x42: cta_displayid_type_10(x + 1, length); return;
case 0x78:
cta_hf_eeodb(x + 1, length);
// This must be the first CTA-861 block
diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp
index 48dfda7..7036860 100644
--- a/parse-displayid-block.cpp
+++ b/parse-displayid-block.cpp
@@ -221,7 +221,8 @@ void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
// tag 0x03 and 0x22
-void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x, bool type7)
+void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
+ bool type7, unsigned block_rev, bool is_cta)
{
struct timings t = {};
unsigned hbl, vbl;
@@ -290,6 +291,8 @@ void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x, bool ty
fail("Reserved stereo 0x03.\n");
break;
}
+ if (block_rev >= 2 && (x[3] & 0x80))
+ s += ", YCbCr 4:2:0";
t.hact = 1 + (x[4] | (x[5] << 8));
hbl = 1 + (x[6] | (x[7] << 8));
@@ -312,7 +315,7 @@ void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x, bool ty
t.vsync /= 2;
t.vbp /= 2;
}
- if (x[3] & 0x80) {
+ if (block_rev < 2 && (x[3] & 0x80)) {
s += ", preferred";
dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
}
@@ -448,7 +451,7 @@ void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
// tag 0x06 and 0x23
-void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id)
+void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
{
const struct timings *t = NULL;
char type_name[16];
@@ -1303,6 +1306,57 @@ void edid_state::parse_displayid_ContainerID(const unsigned char *x)
}
}
+// tag 0x32
+
+void edid_state::parse_displayid_type_10_timing(const unsigned char *x, bool is_cta)
+{
+ struct timings t = {};
+ std::string s("aspect ");
+
+ t.hact = 1 + (x[1] | (x[2] << 8));
+ t.vact = 1 + (x[3] | (x[4] << 8));
+ calc_ratio(&t);
+ s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
+
+ switch ((x[0] >> 5) & 0x3) {
+ case 0:
+ s += ", no 3D stereo";
+ break;
+ case 1:
+ s += ", 3D stereo";
+ break;
+ case 2:
+ s += ", 3D stereo depends on user action";
+ break;
+ case 3:
+ s += ", reserved";
+ fail("Reserved stereo 0x03.\n");
+ break;
+ }
+
+ switch (x[0] & 0x07) {
+ case 1: t.rb = 1; break;
+ case 2: t.rb = 2; break;
+ case 3: t.rb = 3; break;
+ default: break;
+ }
+
+ if (x[0] & 0x10) {
+ if (t.rb == 2)
+ s += ", refresh rate * (1000/1001) supported";
+ else if (t.rb == 3)
+ s += ", hblank is 160 pixels";
+ else
+ fail("VR_HB must be 0.\n");
+ }
+ if (x[0] & 0x80)
+ s += ", YCbCr 4:2:0";
+
+ edid_cvt_mode(1 + x[5], t);
+
+ print_timings(" ", &t, "CVT", s.c_str());
+}
+
// tag 0x7e, OUI 3A-02-92 (VESA)
void edid_state::parse_displayid_vesa(const unsigned char *x)
@@ -1517,6 +1571,7 @@ void edid_state::parse_displayid_block(const unsigned char *x)
case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
case 0x29: data_block = "ContainerID Data Block"; break;
+ case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
// 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
case 0x7e: // DisplayID 2.0
case 0x7f: // DisplayID 1.3
@@ -1541,7 +1596,7 @@ void edid_state::parse_displayid_block(const unsigned char *x)
data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")";
}
break;
- // 0x80 RESERVED
+ // 0x80 RESERVED
case 0x81: data_block = "CTA-861 DisplayID Data Block (" + utohex(tag) + ")"; break;
// 0x82 .. 0xff RESERVED
default: data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")"; break;
@@ -1562,6 +1617,7 @@ void edid_state::parse_displayid_block(const unsigned char *x)
break;
}
+ unsigned block_rev = x[offset + 1] & 0x07;
unsigned len = x[offset + 2];
if (length < len + 3) {
@@ -1584,9 +1640,9 @@ void edid_state::parse_displayid_block(const unsigned char *x)
case 0x01: parse_displayid_parameters(x + offset); break;
case 0x02: parse_displayid_color_characteristics(x + offset); break;
case 0x03:
- check_displayid_datablock_revision(x[offset + 1], 0, x[offset + 1] & 1);
+ check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
for (i = 0; i < len / 20; i++)
- parse_displayid_type_1_7_timing(&x[offset + 3 + (i * 20)], false);
+ parse_displayid_type_1_7_timing(&x[offset + 3 + (i * 20)], false, block_rev);
break;
case 0x04:
check_displayid_datablock_revision(x[offset + 1]);
@@ -1594,7 +1650,7 @@ void edid_state::parse_displayid_block(const unsigned char *x)
parse_displayid_type_2_timing(&x[offset + 3 + (i * 11)]);
break;
case 0x05:
- check_displayid_datablock_revision(x[offset + 1], 0, x[offset + 1] & 1);
+ check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
for (i = 0; i < len / 3; i++)
parse_displayid_type_3_timing(&x[offset + 3 + (i * 3)]);
break;
@@ -1642,19 +1698,27 @@ void edid_state::parse_displayid_block(const unsigned char *x)
break;
case 0x20: parse_displayid_product_id(x + offset); break;
case 0x21: parse_displayid_parameters_v2(x + offset); break;
- case 0x22:
- if (x[offset + 1] & 0x07)
+ case 0x22: {
+ unsigned sz = 20;
+
+ if (block_rev >= 2)
+ check_displayid_datablock_revision(x[offset + 1], 0x08, 2);
+ else if (block_rev == 1)
check_displayid_datablock_revision(x[offset + 1], 0x08, 1);
else
check_displayid_datablock_revision(x[offset + 1]);
-
- if ((x[offset + 1] & 0x07) >= 1 && (x[offset + 1] & 0x08))
+ sz += (x[offset + 1] & 0x70) >> 4;
+ if (block_rev >= 1 && (x[offset + 1] & 0x08))
printf(" These timings support DSC pass-through\n");
- for (i = 0; i < len / 20; i++)
- parse_displayid_type_1_7_timing(&x[offset + 3 + i * 20], true);
+ for (i = 0; i < len / sz; i++)
+ parse_displayid_type_1_7_timing(&x[offset + 3 + i * sz], true, block_rev);
break;
+ }
case 0x23:
- check_displayid_datablock_revision(x[offset + 1], 0xc8);
+ if (block_rev)
+ check_displayid_datablock_revision(x[offset + 1], 0xe8, 1);
+ else
+ check_displayid_datablock_revision(x[offset + 1], 0xc8);
if (x[offset + 1] & 0x08) {
for (i = 0; i < len / 2; i++)
parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6,
@@ -1676,6 +1740,14 @@ void edid_state::parse_displayid_block(const unsigned char *x)
case 0x27: parse_displayid_stereo_display_intf(x + offset); break;
case 0x28: parse_displayid_tiled_display_topology(x + offset, true); break;
case 0x29: parse_displayid_ContainerID(x + offset); break;
+ case 0x32: {
+ unsigned sz = 6 + ((x[offset + 1] & 0x70) >> 4);
+
+ check_displayid_datablock_revision(x[offset + 1], 0x10);
+ for (i = 0; i < len / sz; i++)
+ parse_displayid_type_10_timing(&x[offset + 3 + i * sz]);
+ break;
+ }
case 0x81: parse_displayid_cta_data_block(x + offset); break;
case 0x7e:
if (oui == 0x3a0292) {

Privacy Policy