aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-05-31 15:31:11 +0200
committerHans Verkuil <hverkuil-cisco@xs4all.nl>2021-05-31 15:43:26 +0200
commiteb7831ef61e22dc5be20f9da50e804917aa54f8f (patch)
tree1134ecefe1523752572109865dacece9ec10723f
parenteaee00f196ec4081b2a2dfcde71f46b9097e9bf5 (diff)
edid-decode: add DisplayID 2.0 E8 Type X support
Implement the changes for Type X defined in the DisplayID 2.0 E8 errata document. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-rw-r--r--calc-gtf-cvt.cpp18
-rw-r--r--edid-decode.19
-rw-r--r--edid-decode.cpp13
-rw-r--r--edid-decode.h8
-rw-r--r--parse-cta-block.cpp7
-rw-r--r--parse-displayid-block.cpp40
6 files changed, 75 insertions, 20 deletions
diff --git a/calc-gtf-cvt.cpp b/calc-gtf-cvt.cpp
index bc32ea0..36f89f2 100644
--- a/calc-gtf-cvt.cpp
+++ b/calc-gtf-cvt.cpp
@@ -128,7 +128,8 @@ void edid_state::edid_gtf_mode(unsigned refresh, struct timings &t)
// If rb == RB_CVT_V3, then alt means that rb_h_blank is 160 instead of 80.
timings edid_state::calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
double ip_freq_rqd, unsigned rb, bool int_rqd,
- bool margins_rqd, bool alt, unsigned rb_h_blank)
+ bool margins_rqd, bool alt, unsigned rb_h_blank,
+ double add_vert_time)
{
timings t = {};
@@ -149,6 +150,7 @@ timings edid_state::calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
double h_blank = (rb == RB_CVT_V1 || (rb == RB_CVT_V3 && alt)) ? 160 : 80;
double rb_v_fporch = rb == RB_CVT_V1 ? 3 : 1;
double refresh_multiplier = (rb == RB_CVT_V2 && alt) ? 1000.0 / 1001.0 : 1;
+ double rb_min_vblank = CVT_RB_MIN_VBLANK;
double h_sync = 32;
double v_sync;
@@ -156,6 +158,11 @@ timings edid_state::calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
double v_blank;
double v_sync_bp;
+ if (rb == RB_CVT_V3 && add_vert_time) {
+ if (add_vert_time + rb_min_vblank <= 1000000.0 / ip_freq_rqd / 4.0)
+ rb_min_vblank += add_vert_time;
+ }
+
if (rb == RB_CVT_V3 && rb_h_blank) {
h_blank = rb_h_blank & ~7;
if (h_blank < 80)
@@ -198,9 +205,9 @@ timings edid_state::calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
h_sync = floor(total_pixels * 0.08 / CELL_GRAN) * CELL_GRAN;
pixel_freq = floor((total_pixels / h_period_est) / clock_step) * clock_step;
} else {
- double h_period_est = ((1000000.0 / v_field_rate_rqd) - CVT_RB_MIN_VBLANK) /
+ double h_period_est = ((1000000.0 / v_field_rate_rqd) - rb_min_vblank) /
(v_lines_rnd + vert_margin * 2);
- double vbi_lines = floor(CVT_RB_MIN_VBLANK / h_period_est) + 1;
+ double vbi_lines = floor(rb_min_vblank / h_period_est) + 1;
double rb_min_vbi = rb_v_fporch + v_sync + CVT_MIN_V_BPORCH;
v_blank = vbi_lines < rb_min_vbi ? rb_min_vbi : vbi_lines;
double total_v_lines = v_blank + v_lines_rnd + vert_margin * 2 + interlace;
@@ -237,13 +244,14 @@ timings edid_state::calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
return t;
}
-void edid_state::edid_cvt_mode(unsigned refresh, struct timings &t)
+void edid_state::edid_cvt_mode(unsigned refresh, struct timings &t, unsigned rb_h_blank,
+ double add_vert_time)
{
unsigned hratio = t.hratio;
unsigned vratio = t.vratio;
t = calc_cvt_mode(t.hact, t.vact, refresh, t.rb & ~RB_ALT, t.interlaced,
- false, t.rb & RB_ALT);
+ false, t.rb & RB_ALT, rb_h_blank, add_vert_time);
t.hratio = hratio;
t.vratio = vratio;
}
diff --git a/edid-decode.1 b/edid-decode.1
index ecd7fe3..5bb69d1 100644
--- a/edid-decode.1
+++ b/edid-decode.1
@@ -113,7 +113,7 @@ DisplayID 1.3: VESA Display Identification Data (DisplayID) Standard, Version 1.
.TP
DisplayID 2.0: VESA DisplayID Standard, Version 2.0
.TP
-DisplayID 2.0: VESA DisplayID v2.0 Errata E7
+DisplayID 2.0: VESA DisplayID v2.0 Errata E8
.TP
DI-EXT: VESA Display Information Extension Block Standard, Release A
.TP
@@ -255,7 +255,8 @@ Show the timings for this VIC.
\fB\-\-hdmi\-vic\fR \fI<hdmivic>\fR
Show the timings for this HDMI VIC.
.TP
-\fB\-\-cvt\fR \fBw\fR=\fI<width>\fR,\fBh\fR=\fI<height>\fR,\fBfps\fR=\fI<fps>\fR[,\fBrb\fR=\fI<rb>\fR][,\fBinterlaced\fR][,\fBoverscan\fR][,\fBalt\fR][,\fBhblank\fR=\fI<hblank>\fR]
+\fB\-\-cvt\fR \fBw\fR=\fI<width>\fR,\fBh\fR=\fI<height>\fR,\fBfps\fR=\fI<fps>\fR[,\fBrb\fR=\fI<rb>\fR][,\fBinterlaced\fR][,\fBoverscan\fR]
+[,\fBalt\fR][,\fBhblank\fR=\fI<hblank>\fR][,\fBadd\-vblank\fR=\fI<add\-vblank>\fR]
.br
Calculate the CVT timings for the given format.
@@ -277,6 +278,10 @@ is 160 instead of 80 pixels.
.br
If \fBhblank\fR is given and \fI<rb>\fR=3, then the horizontal blanking
is \fI<hblank>\fR pixels (range of 80-200 and divisible by 8), overriding \fBalt\fR.
+.br
+If \fBadd\-vblank\fR is given and \fI<rb>\fR=3, then \fI<add\-vblank>\fR microseconds are
+added to the minimum vertical blank time of 460 microseconds as long as the total blank
+time does not exceed 25% of the frame time.
.TP
\fB\-\-gtf\fR \fBw\fR=\fI<width>\fR,\fBh\fR=\fI<height>\fR[,\fBfps\fR=\fI<fps>\fR][,\fBhorfreq\fR=\fI<horfreq>\fR][,\fBpixclk\fR=\fI<pixclk>\fR]
[,\fBinterlaced\fR][,\fBoverscan\fR][,\fBsecondary\fR][,\fBC\fR=\fI<c>\fR][,\fBM\fR=\fI<m>\fR][,\fBK\fR=\fI<k>\fR][,\fBJ\fR=\fI<j>\fR]
diff --git a/edid-decode.cpp b/edid-decode.cpp
index de70242..2316abc 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -139,7 +139,7 @@ static void usage(void)
" --dmt <dmt> Show the timings for the DMT with the given DMT ID.\n"
" --vic <vic> Show the timings for this VIC.\n"
" --hdmi-vic <hdmivic> Show the timings for this HDMI VIC.\n"
- " --cvt w=<width>,h=<height>,fps=<fps>[,rb=<rb>][,interlaced][,overscan][,alt][,hblank=<hblank]\n"
+ " --cvt w=<width>,h=<height>,fps=<fps>[,rb=<rb>][,interlaced][,overscan][,alt][,hblank=<hblank][,add-vblank=<add-vblank>\n"
" Calculate the CVT timings for the given format.\n"
" <fps> is frames per second for progressive timings,\n"
" or fields per second for interlaced timings.\n"
@@ -153,6 +153,8 @@ static void usage(void)
" is 160 instead of 80 pixels.\n"
" If 'hblank' is given and <rb>=3, then the horizontal blanking\n"
" is <hblank> pixels (range of 80-200), overriding 'alt'.\n"
+ " If 'add-vblank' is given and <rb>=3, then <add-vblank> usecs are\n"
+ " added to the minimum vertical blank time of 460 usecs.\n"
" --gtf w=<width>,h=<height>[,fps=<fps>][,horfreq=<horfreq>][,pixclk=<pixclk>][,interlaced]\n"
" [,overscan][,secondary][,C=<c>][,M=<m>][,K=<k>][,J=<j>]\n"
" Calculate the GTF timings for the given format.\n"
@@ -1335,6 +1337,7 @@ enum cvt_opts {
CVT_RB,
CVT_ALT,
CVT_RB_H_BLANK,
+ CVT_RB_ADD_V_BLANK,
};
static int parse_cvt_subopt(char **subopt_str, double *value)
@@ -1351,6 +1354,7 @@ static int parse_cvt_subopt(char **subopt_str, double *value)
"rb",
"alt",
"hblank",
+ "add-vblank",
nullptr
};
@@ -1380,6 +1384,7 @@ static void parse_cvt(char *optarg)
double fps = 0;
unsigned rb = RB_NONE;
unsigned rb_h_blank = 0;
+ unsigned rb_add_v_blank = 0;
bool interlaced = false;
bool alt = false;
bool overscan = false;
@@ -1415,6 +1420,9 @@ static void parse_cvt(char *optarg)
case CVT_RB_H_BLANK:
rb_h_blank = opt_val;
break;
+ case CVT_RB_ADD_V_BLANK:
+ rb_add_v_blank = opt_val;
+ break;
default:
break;
}
@@ -1427,7 +1435,8 @@ static void parse_cvt(char *optarg)
}
if (interlaced)
fps /= 2;
- timings t = state.calc_cvt_mode(w, h, fps, rb, interlaced, overscan, alt, rb_h_blank);
+ timings t = state.calc_cvt_mode(w, h, fps, rb, interlaced, overscan, alt,
+ rb_h_blank, rb_add_v_blank);
state.print_timings("", &t, "CVT", "", true, false);
}
diff --git a/edid-decode.h b/edid-decode.h
index f3fdfd0..234a7b5 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -314,8 +314,9 @@ struct edid_state {
timings calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
double ip_freq_rqd, unsigned rb, bool int_rqd = false,
bool margins_rqd = false, bool alt = false,
- unsigned rb_h_blank = 0);
- void edid_cvt_mode(unsigned refresh, struct timings &t);
+ unsigned rb_h_blank = 0, double add_vert_time = 0);
+ void edid_cvt_mode(unsigned refresh, struct timings &t, unsigned rb_h_blank = 0,
+ double add_vert_time = 0);
void detailed_cvt_descriptor(const char *prefix, const unsigned char *x, bool first);
void print_standard_timing(const char *prefix, unsigned char b1, unsigned char b2,
bool gtf_only = false, bool show_both = false);
@@ -386,7 +387,8 @@ 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 parse_displayid_type_10_timing(const unsigned char *x, unsigned sz,
+ unsigned block_rev, 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 6ce8e6c..fed3625 100644
--- a/parse-cta-block.cpp
+++ b/parse-cta-block.cpp
@@ -1898,7 +1898,10 @@ void edid_state::cta_displayid_type_8(const unsigned char *x, unsigned length)
void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
{
- check_displayid_datablock_revision(x[0], 0x70);
+ if (x[0] & 7)
+ check_displayid_datablock_revision(x[0], 0x70, 1);
+ else
+ check_displayid_datablock_revision(x[0], 0x70);
if (length < 7U + ((x[0] & 0x70) >> 4)) {
fail("Empty Data Block with length %u.\n", length);
return;
@@ -1908,7 +1911,7 @@ void edid_state::cta_displayid_type_10(const unsigned char *x, unsigned length)
x++;
length--;
for (unsigned i = 0; i < length / sz; i++)
- parse_displayid_type_10_timing(x + i * sz, true);
+ parse_displayid_type_10_timing(x + i * sz, sz, x[0] & 7, true);
}
static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp
index 5bd9734..606d16e 100644
--- a/parse-displayid-block.cpp
+++ b/parse-displayid-block.cpp
@@ -1366,7 +1366,9 @@ 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)
+void edid_state::parse_displayid_type_10_timing(const unsigned char *x,
+ unsigned sz, unsigned block_rev,
+ bool is_cta)
{
struct timings t = {};
std::string s("aspect ");
@@ -1399,13 +1401,17 @@ void edid_state::parse_displayid_type_10_timing(const unsigned char *x, bool is_
default: break;
}
+ unsigned rb = t.rb;
+ unsigned rb_h_blank = rb == RB_CVT_V3 ? 80 : 0;
+
if (x[0] & 0x10) {
- if (t.rb == RB_CVT_V2) {
+ if (rb == RB_CVT_V2) {
s += ", refresh rate * (1000/1001) supported";
t.rb |= RB_ALT;
- } else if (t.rb == RB_CVT_V3) {
+ } else if (rb == RB_CVT_V3) {
s += ", hblank is 160 pixels";
t.rb |= RB_ALT;
+ rb_h_blank = 160;
} else {
fail("VR_HB must be 0.\n");
}
@@ -1413,7 +1419,25 @@ void edid_state::parse_displayid_type_10_timing(const unsigned char *x, bool is_
if (x[0] & 0x80)
s += ", YCbCr 4:2:0";
- edid_cvt_mode(1 + x[5], t);
+ unsigned refresh = 1 + x[5] + (sz == 6 ? 0 : ((x[6] & 3) << 8));
+ double add_vert_time = 0;
+
+ if (sz > 6 && block_rev > 0 && rb == RB_CVT_V3) {
+ unsigned delta_hblank = (x[6] >> 2) & 7;
+
+ if (rb_h_blank == 80)
+ rb_h_blank = 80 + 8 * delta_hblank;
+ else if (delta_hblank <= 5)
+ rb_h_blank = 160 + 8 * delta_hblank;
+ else
+ rb_h_blank = 160 - (delta_hblank - 5) * 8;
+
+ unsigned vblank_time_perc = (x[6] >> 5) & 7;
+
+ add_vert_time = (vblank_time_perc * 10000.0) / refresh;
+ }
+
+ edid_cvt_mode(refresh, t, rb_h_blank, add_vert_time);
print_timings(" ", &t, "CVT", s.c_str());
if (is_cta) {
@@ -1823,9 +1847,13 @@ void edid_state::parse_displayid_block(const unsigned char *x)
case 0x32: {
unsigned sz = 6 + ((x[offset + 1] & 0x70) >> 4);
- check_displayid_datablock_revision(x[offset + 1], 0x10);
+ if (block_rev)
+ check_displayid_datablock_revision(x[offset + 1], 0x70, 1);
+ else
+ check_displayid_datablock_revision(x[offset + 1], 0x70);
for (i = 0; i < len / sz; i++)
- parse_displayid_type_10_timing(&x[offset + 3 + i * sz]);
+ parse_displayid_type_10_timing(&x[offset + 3 + i * sz],
+ sz, block_rev);
break;
}
case 0x81: parse_displayid_cta_data_block(x + offset); break;

Privacy Policy