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 /* Minimum vertical backporch for CVT and CVT RBv1 */
123 #define CVT_MIN_V_BPORCH 7
124 /* Fixed vertical backporch for CVT RBv2 and RBv3 */
125 #define CVT_FIXED_V_BPORCH 6
126 #define CVT_C_PRIME 30.0
127 #define CVT_M_PRIME 300.0
128 #define CVT_RB_MIN_VBLANK 460.0
130 // If rb == RB_CVT_V2, then alt means video-optimized (i.e. 59.94 instead of 60 Hz, etc.).
131 // If rb == RB_CVT_V3, then alt means that rb_h_blank is 160 instead of 80.
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
, unsigned rb_h_blank
,
135 double add_vert_time
)
141 t
.interlaced
= int_rqd
;
143 double cell_gran
= rb
== RB_CVT_V2
? 1 : CELL_GRAN
;
144 double h_pixels_rnd
= floor(h_pixels
/ cell_gran
) * cell_gran
;
145 double v_lines_rnd
= int_rqd
? floor(v_lines
/ 2.0) : v_lines
;
146 unsigned hor_margin
= margins_rqd
?
147 floor((h_pixels_rnd
* MARGIN_PERC
/ 100.0) / cell_gran
) * cell_gran
: 0;
148 unsigned vert_margin
= margins_rqd
? floor(MARGIN_PERC
/ 100.0 * v_lines_rnd
) : 0;
149 double interlace
= int_rqd
? 0.5 : 0;
150 double total_active_pixels
= h_pixels_rnd
+ hor_margin
* 2;
151 double v_field_rate_rqd
= int_rqd
? ip_freq_rqd
* 2 : ip_freq_rqd
;
152 double clock_step
= rb
== RB_CVT_V2
? 0.001 : 0.25;
153 double h_blank
= (rb
== RB_CVT_V1
|| (rb
== RB_CVT_V3
&& alt
)) ? 160 : 80;
154 double rb_v_fporch
= rb
== RB_CVT_V1
? 3 : 1;
155 double refresh_multiplier
= (rb
== RB_CVT_V2
&& alt
) ? 1000.0 / 1001.0 : 1;
156 double rb_min_vblank
= CVT_RB_MIN_VBLANK
;
164 if (rb
== RB_CVT_V3
&& add_vert_time
) {
165 if (add_vert_time
+ rb_min_vblank
<= 1000000.0 / ip_freq_rqd
/ 4.0)
166 rb_min_vblank
+= add_vert_time
;
169 if (rb
== RB_CVT_V3
&& rb_h_blank
) {
170 h_blank
= rb_h_blank
& ~7;
173 else if (h_blank
> 200)
177 /* Determine VSync Width from aspect ratio */
178 if ((t
.vact
* 4 / 3) == t
.hact
)
180 else if ((t
.vact
* 16 / 9) == t
.hact
)
182 else if ((t
.vact
* 16 / 10) == t
.hact
)
184 else if (!(t
.vact
% 4) && ((t
.vact
* 5 / 4) == t
.hact
))
186 else if ((t
.vact
* 15 / 9) == t
.hact
)
195 double h_period_est
= ((1.0 / v_field_rate_rqd
) - CVT_MIN_VSYNC_BP
/ 1000000.0) /
196 (v_lines_rnd
+ vert_margin
* 2 + CVT_MIN_V_PORCH
+ interlace
) * 1000000.0;
197 v_sync_bp
= floor(CVT_MIN_VSYNC_BP
/ h_period_est
) + 1;
198 if (v_sync_bp
< v_sync
+ CVT_MIN_V_BPORCH
)
199 v_sync_bp
= v_sync
+ CVT_MIN_V_BPORCH
;
200 v_blank
= v_sync_bp
+ CVT_MIN_V_PORCH
;
201 double ideal_duty_cycle
= CVT_C_PRIME
- (CVT_M_PRIME
* h_period_est
/ 1000.0);
202 if (ideal_duty_cycle
< 20)
203 ideal_duty_cycle
= 20;
204 h_blank
= floor(total_active_pixels
* ideal_duty_cycle
/
205 (100.0 - ideal_duty_cycle
) /
206 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
207 double total_pixels
= total_active_pixels
+ h_blank
;
208 h_sync
= floor(total_pixels
* 0.08 / CELL_GRAN
) * CELL_GRAN
;
209 pixel_freq
= floor((total_pixels
/ h_period_est
) / clock_step
) * clock_step
;
211 double h_period_est
= ((1000000.0 / v_field_rate_rqd
) - rb_min_vblank
) /
212 (v_lines_rnd
+ vert_margin
* 2);
213 double vbi_lines
= floor(rb_min_vblank
/ h_period_est
) + 1;
214 double rb_min_vbi
= rb_v_fporch
+ v_sync
+
215 (rb
== RB_CVT_V1
? CVT_MIN_V_BPORCH
: CVT_FIXED_V_BPORCH
);
216 v_blank
= vbi_lines
< rb_min_vbi
? rb_min_vbi
: vbi_lines
;
217 double total_v_lines
= v_blank
+ v_lines_rnd
+ vert_margin
* 2 + interlace
;
219 v_sync_bp
= v_blank
- rb_v_fporch
;
221 v_sync_bp
= v_sync
+ CVT_FIXED_V_BPORCH
;
222 double total_pixels
= h_blank
+ total_active_pixels
;
223 double freq
= v_field_rate_rqd
* total_v_lines
* total_pixels
* refresh_multiplier
;
225 pixel_freq
= ceil((freq
/ 1000000.0) / clock_step
) * clock_step
;
227 pixel_freq
= floor((freq
/ 1000000.0) / clock_step
) * clock_step
;
230 t
.vbp
= v_sync_bp
- v_sync
;
232 t
.vfp
= v_blank
- t
.vbp
- t
.vsync
;
233 t
.pixclk_khz
= round(1000.0 * pixel_freq
);
238 t
.hfp
= (h_blank
/ 2.0) - t
.hsync
;
239 t
.hbp
= h_blank
- t
.hfp
- t
.hsync
;
240 t
.hborder
= hor_margin
;
241 t
.vborder
= vert_margin
;
243 if (alt
&& (rb
== RB_CVT_V2
|| rb
== RB_CVT_V3
))
245 t
.pos_pol_hsync
= t
.rb
;
246 t
.pos_pol_vsync
= !t
.rb
;
251 void edid_state::edid_cvt_mode(unsigned refresh
, struct timings
&t
, unsigned rb_h_blank
,
252 double add_vert_time
)
254 unsigned hratio
= t
.hratio
;
255 unsigned vratio
= t
.vratio
;
257 t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, t
.rb
& ~RB_ALT
, t
.interlaced
,
258 false, t
.rb
& RB_ALT
, rb_h_blank
, add_vert_time
);