1 // SPDX-License-Identifier: MIT
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2021 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>
15 #include "edid-decode.h"
18 #define MARGIN_PERC 1.8
19 #define GTF_MIN_PORCH 1.0
20 #define GTF_V_SYNC_RQD 3.0
21 #define GTF_H_SYNC_PERC 8.0
22 #define GTF_MIN_VSYNC_BP 550.0
24 timings
edid_state::calc_gtf_mode(unsigned h_pixels
, unsigned v_lines
,
25 double ip_freq_rqd
, bool int_rqd
,
26 enum gtf_ip_parm ip_parm
, bool margins_rqd
,
27 bool secondary
, double C
, double M
, double K
, double J
)
30 /* C' and M' are part of the Blanking Duty Cycle computation */
31 double C_PRIME
= ((C
- J
) * K
/ 256.0) + J
;
32 double M_PRIME
= K
/ 256.0 * M
;
34 double h_pixels_rnd
= round(h_pixels
/ CELL_GRAN
) * CELL_GRAN
;
35 double v_lines_rnd
= int_rqd
? round(v_lines
/ 2.0) : v_lines
;
36 unsigned hor_margin
= margins_rqd
?
37 round(h_pixels_rnd
* MARGIN_PERC
/ 100.0 / CELL_GRAN
) * CELL_GRAN
: 0;
38 unsigned vert_margin
= margins_rqd
? round(MARGIN_PERC
/ 100.0 * v_lines_rnd
) : 0;
39 double interlace
= int_rqd
? 0.5 : 0;
40 double total_active_pixels
= h_pixels_rnd
+ hor_margin
* 2;
42 t
.hact
= h_pixels_rnd
;
44 t
.interlaced
= int_rqd
;
47 double h_blank_pixels
;
51 if (ip_parm
== gtf_ip_vert_freq
) {
52 // vertical frame frequency (Hz)
53 double v_field_rate_rqd
= int_rqd
? ip_freq_rqd
* 2 : ip_freq_rqd
;
54 double h_period_est
= ((1.0 / v_field_rate_rqd
) - GTF_MIN_VSYNC_BP
/ 1000000.0) /
55 (v_lines_rnd
+ vert_margin
* 2 + GTF_MIN_PORCH
+ interlace
) * 1000000.0;
56 v_sync_bp
= round(GTF_MIN_VSYNC_BP
/ h_period_est
);
57 double total_v_lines
= v_lines_rnd
+ vert_margin
* 2 +
58 v_sync_bp
+ interlace
+ GTF_MIN_PORCH
;
59 double v_field_rate_est
= 1.0 / h_period_est
/ total_v_lines
* 1000000.0;
60 double h_period
= h_period_est
/ (v_field_rate_rqd
/ v_field_rate_est
);
61 double ideal_duty_cycle
= C_PRIME
- (M_PRIME
* h_period
/ 1000.0);
62 h_blank_pixels
= round(total_active_pixels
* ideal_duty_cycle
/
63 (100.0 - ideal_duty_cycle
) /
64 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
65 total_pixels
= total_active_pixels
+ h_blank_pixels
;
66 pixel_freq
= total_pixels
/ h_period
;
67 } else if (ip_parm
== gtf_ip_hor_freq
) {
68 // horizontal frequency (kHz)
69 double h_freq
= ip_freq_rqd
;
70 v_sync_bp
= round(GTF_MIN_VSYNC_BP
* h_freq
/ 1000.0);
71 double ideal_duty_cycle
= C_PRIME
- (M_PRIME
/ h_freq
);
72 h_blank_pixels
= round(total_active_pixels
* ideal_duty_cycle
/
73 (100.0 - ideal_duty_cycle
) /
74 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
75 total_pixels
= total_active_pixels
+ h_blank_pixels
;
76 pixel_freq
= total_pixels
* h_freq
/ 1000.0;
78 // pixel clock rate (MHz)
79 pixel_freq
= ip_freq_rqd
;
80 double ideal_h_period
=
82 sqrt(((100.0 - C_PRIME
) * (100.0 - C_PRIME
) +
83 (0.4 * M_PRIME
* (total_active_pixels
+ hor_margin
* 2) /
84 pixel_freq
)))) / 2.0 / M_PRIME
* 1000.0;
85 double ideal_duty_cycle
= C_PRIME
- (M_PRIME
* ideal_h_period
) / 1000.0;
86 h_blank_pixels
= round(total_active_pixels
* ideal_duty_cycle
/
87 (100.0 - ideal_duty_cycle
) /
88 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
89 total_pixels
= total_active_pixels
+ h_blank_pixels
;
90 double h_freq
= pixel_freq
/ total_pixels
* 1000.0;
91 v_sync_bp
= round(GTF_MIN_VSYNC_BP
* h_freq
/ 1000.0);
94 double v_back_porch
= v_sync_bp
- GTF_V_SYNC_RQD
;
97 t
.vsync
= GTF_V_SYNC_RQD
;
98 t
.vfp
= GTF_MIN_PORCH
;
99 t
.pixclk_khz
= round(1000.0 * pixel_freq
);
100 t
.hsync
= round(GTF_H_SYNC_PERC
/ 100.0 * total_pixels
/ CELL_GRAN
) * CELL_GRAN
;
101 t
.hfp
= (h_blank_pixels
/ 2.0) - t
.hsync
;
102 t
.hbp
= t
.hfp
+ t
.hsync
;
103 t
.hborder
= hor_margin
;
104 t
.vborder
= vert_margin
;
105 t
.pos_pol_hsync
= secondary
;
106 t
.pos_pol_vsync
= !secondary
;
107 t
.rb
= secondary
? RB_GTF
: RB_NONE
;
111 void edid_state::edid_gtf_mode(unsigned refresh
, struct timings
&t
)
113 unsigned hratio
= t
.hratio
;
114 unsigned vratio
= t
.vratio
;
115 t
= calc_gtf_mode(t
.hact
, t
.vact
, refresh
, t
.interlaced
);
120 #define CVT_MIN_VSYNC_BP 550.0
121 #define CVT_MIN_V_PORCH 3
122 #define CVT_MIN_V_BPORCH 6
123 #define CVT_C_PRIME 30.0
124 #define CVT_M_PRIME 300.0
125 #define CVT_RB_MIN_VBLANK 460.0
127 // If rb == RB_CVT_V2, then alt means video-optimized (i.e. 59.94 instead of 60 Hz, etc.).
128 // If rb == RB_CVT_V3, then alt means that rb_h_blank is 160 instead of 80.
129 // Note: for RB_CVT_V3 this calculation is slightly different, but
130 // since CVT 1.3 is not yet public, I cannot update the calculation yet. For now
131 // it will follow V2. So RBv3 timings will be off for now.
132 timings
edid_state::calc_cvt_mode(unsigned h_pixels
, unsigned v_lines
,
133 double ip_freq_rqd
, unsigned rb
, bool int_rqd
,
134 bool margins_rqd
, bool alt
)
140 t
.interlaced
= int_rqd
;
142 double cell_gran
= rb
== RB_CVT_V2
? 1 : CELL_GRAN
;
143 double h_pixels_rnd
= floor(h_pixels
/ cell_gran
) * cell_gran
;
144 double v_lines_rnd
= int_rqd
? floor(v_lines
/ 2.0) : v_lines
;
145 unsigned hor_margin
= margins_rqd
?
146 floor((h_pixels_rnd
* MARGIN_PERC
/ 100.0) / cell_gran
) * cell_gran
: 0;
147 unsigned vert_margin
= margins_rqd
? floor(MARGIN_PERC
/ 100.0 * v_lines_rnd
) : 0;
148 double interlace
= int_rqd
? 0.5 : 0;
149 double total_active_pixels
= h_pixels_rnd
+ hor_margin
* 2;
150 double v_field_rate_rqd
= int_rqd
? ip_freq_rqd
* 2 : ip_freq_rqd
;
151 double clock_step
= rb
== RB_CVT_V2
? 0.001 : 0.25;
152 double h_blank
= (rb
== RB_CVT_V1
|| (rb
== RB_CVT_V3
&& alt
)) ? 160 : 80;
153 double rb_v_fporch
= rb
== RB_CVT_V1
? 3 : 1;
154 double refresh_multiplier
= (rb
== RB_CVT_V2
&& alt
) ? 1000.0 / 1001.0 : 1;
162 /* Determine VSync Width from aspect ratio */
163 if ((t
.vact
* 4 / 3) == t
.hact
)
165 else if ((t
.vact
* 16 / 9) == t
.hact
)
167 else if ((t
.vact
* 16 / 10) == t
.hact
)
169 else if (!(t
.vact
% 4) && ((t
.vact
* 5 / 4) == t
.hact
))
171 else if ((t
.vact
* 15 / 9) == t
.hact
)
180 double h_period_est
= ((1.0 / v_field_rate_rqd
) - CVT_MIN_VSYNC_BP
/ 1000000.0) /
181 (v_lines_rnd
+ vert_margin
* 2 + CVT_MIN_V_PORCH
+ interlace
) * 1000000.0;
182 v_sync_bp
= floor(CVT_MIN_VSYNC_BP
/ h_period_est
) + 1;
183 if (v_sync_bp
< v_sync
+ CVT_MIN_V_BPORCH
)
184 v_sync_bp
= v_sync
+ CVT_MIN_V_BPORCH
;
185 v_blank
= v_sync_bp
+ CVT_MIN_V_PORCH
;
186 double ideal_duty_cycle
= CVT_C_PRIME
- (CVT_M_PRIME
* h_period_est
/ 1000.0);
187 if (ideal_duty_cycle
< 20)
188 ideal_duty_cycle
= 20;
189 h_blank
= floor(total_active_pixels
* ideal_duty_cycle
/
190 (100.0 - ideal_duty_cycle
) /
191 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
192 double total_pixels
= total_active_pixels
+ h_blank
;
193 h_sync
= floor(total_pixels
* 0.08 / CELL_GRAN
) * CELL_GRAN
;
194 pixel_freq
= floor((total_pixels
/ h_period_est
) / clock_step
) * clock_step
;
196 double h_period_est
= ((1000000.0 / v_field_rate_rqd
) - CVT_RB_MIN_VBLANK
) /
197 (v_lines_rnd
+ vert_margin
* 2);
198 double vbi_lines
= floor(CVT_RB_MIN_VBLANK
/ h_period_est
) + 1;
199 double rb_min_vbi
= rb_v_fporch
+ v_sync
+ CVT_MIN_V_BPORCH
;
200 v_blank
= vbi_lines
< rb_min_vbi
? rb_min_vbi
: vbi_lines
;
201 double total_v_lines
= v_blank
+ v_lines_rnd
+ vert_margin
* 2 + interlace
;
203 v_sync_bp
= v_blank
- rb_v_fporch
;
205 v_sync_bp
= v_sync
+ CVT_MIN_V_BPORCH
;
206 double total_pixels
= h_blank
+ total_active_pixels
;
207 pixel_freq
= floor((v_field_rate_rqd
* total_v_lines
* total_pixels
/ 1000000.0 *
208 refresh_multiplier
) / clock_step
) * clock_step
;
211 t
.vbp
= v_sync_bp
- v_sync
;
213 t
.vfp
= v_blank
- t
.vbp
- t
.vsync
;
214 t
.pixclk_khz
= round(1000.0 * pixel_freq
);
216 t
.hfp
= (h_blank
/ 2.0) - t
.hsync
;
217 t
.hbp
= t
.hfp
+ t
.hsync
;
218 t
.hborder
= hor_margin
;
219 t
.vborder
= vert_margin
;
221 if (alt
&& (rb
== RB_CVT_V2
|| rb
== RB_CVT_V3
))
223 t
.pos_pol_hsync
= t
.rb
;
224 t
.pos_pol_vsync
= !t
.rb
;
229 void edid_state::edid_cvt_mode(unsigned refresh
, struct timings
&t
)
231 unsigned hratio
= t
.hratio
;
232 unsigned vratio
= t
.vratio
;
234 t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, t
.rb
& ~RB_ALT
, t
.interlaced
,
235 false, t
.rb
& RB_ALT
);