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
129 #define CVT_RB_ALT_MIN_VBLANK 300.0
131 // If rb == RB_CVT_V2, then alt means video-optimized (i.e. 59.94 instead of 60 Hz, etc.).
132 // If rb == RB_CVT_V3, then alt means that rb_h_blank is 160 instead of 80.
133 timings
edid_state::calc_cvt_mode(unsigned h_pixels
, unsigned v_lines
,
134 double ip_freq_rqd
, unsigned rb
, bool int_rqd
,
135 bool margins_rqd
, bool alt
, unsigned rb_h_blank
,
136 unsigned rb_v_blank
, bool early_vsync_rqd
)
142 t
.interlaced
= int_rqd
;
144 if (rb
== RB_CVT_V3
) {
145 if (rb_v_blank
< CVT_RB_ALT_MIN_VBLANK
)
146 rb_v_blank
= CVT_RB_ALT_MIN_VBLANK
;
147 else if (rb_v_blank
> CVT_RB_ALT_MIN_VBLANK
+ 140 &&
148 rb_v_blank
< CVT_RB_MIN_VBLANK
)
149 rb_v_blank
= CVT_RB_MIN_VBLANK
;
150 else if (rb_v_blank
> CVT_RB_MIN_VBLANK
+ 460)
151 rb_v_blank
= CVT_RB_MIN_VBLANK
+ 460;
154 double cell_gran
= rb
== RB_CVT_V2
? 1 : CELL_GRAN
;
155 double h_pixels_rnd
= floor(h_pixels
/ cell_gran
) * cell_gran
;
156 double v_lines_rnd
= int_rqd
? floor(v_lines
/ 2.0) : v_lines
;
157 unsigned hor_margin
= margins_rqd
?
158 floor((h_pixels_rnd
* MARGIN_PERC
/ 100.0) / cell_gran
) * cell_gran
: 0;
159 unsigned vert_margin
= margins_rqd
? floor(MARGIN_PERC
/ 100.0 * v_lines_rnd
) : 0;
160 double interlace
= int_rqd
? 0.5 : 0;
161 double total_active_pixels
= h_pixels_rnd
+ hor_margin
* 2;
162 double v_field_rate_rqd
= int_rqd
? ip_freq_rqd
* 2 : ip_freq_rqd
;
163 double clock_step
= rb
>= RB_CVT_V2
? 0.001 : 0.25;
164 double h_blank
= (rb
== RB_CVT_V1
|| (rb
== RB_CVT_V3
&& alt
)) ? 160 : 80;
165 double rb_v_fporch
= rb
== RB_CVT_V1
? 3 : 1;
166 double refresh_multiplier
= (rb
== RB_CVT_V2
&& alt
) ? 1000.0 / 1001.0 : 1;
167 double rb_min_vblank
= rb
== RB_CVT_V3
? rb_v_blank
: CVT_RB_MIN_VBLANK
;
175 if (rb
== RB_CVT_V3
&& rb_h_blank
) {
176 h_blank
= rb_h_blank
& ~7;
179 else if (h_blank
> 200)
183 /* Determine VSync Width from aspect ratio */
184 if ((t
.vact
* 4 / 3) == t
.hact
)
186 else if ((t
.vact
* 16 / 9) == t
.hact
)
188 else if ((t
.vact
* 16 / 10) == t
.hact
)
190 else if (!(t
.vact
% 4) && ((t
.vact
* 5 / 4) == t
.hact
))
192 else if ((t
.vact
* 15 / 9) == t
.hact
)
201 double h_period_est
= ((1.0 / v_field_rate_rqd
) - CVT_MIN_VSYNC_BP
/ 1000000.0) /
202 (v_lines_rnd
+ vert_margin
* 2 + CVT_MIN_V_PORCH
+ interlace
) * 1000000.0;
203 v_sync_bp
= floor(CVT_MIN_VSYNC_BP
/ h_period_est
) + 1;
204 if (v_sync_bp
< v_sync
+ CVT_MIN_V_BPORCH
)
205 v_sync_bp
= v_sync
+ CVT_MIN_V_BPORCH
;
206 v_blank
= v_sync_bp
+ CVT_MIN_V_PORCH
;
207 double ideal_duty_cycle
= CVT_C_PRIME
- (CVT_M_PRIME
* h_period_est
/ 1000.0);
208 if (ideal_duty_cycle
< 20)
209 ideal_duty_cycle
= 20;
210 h_blank
= floor(total_active_pixels
* ideal_duty_cycle
/
211 (100.0 - ideal_duty_cycle
) /
212 (2 * CELL_GRAN
)) * 2 * CELL_GRAN
;
213 double total_pixels
= total_active_pixels
+ h_blank
;
214 h_sync
= floor(total_pixels
* 0.08 / CELL_GRAN
) * CELL_GRAN
;
215 pixel_freq
= floor((total_pixels
/ h_period_est
) / clock_step
) * clock_step
;
217 double h_period_est
= ((1000000.0 / v_field_rate_rqd
) - rb_min_vblank
) /
218 (v_lines_rnd
+ vert_margin
* 2);
219 double vbi_lines
= floor(rb_min_vblank
/ h_period_est
) + 1;
220 double rb_v_bporch
= (rb
== RB_CVT_V1
? CVT_MIN_V_BPORCH
: CVT_FIXED_V_BPORCH
);
221 double rb_min_vbi
= rb_v_fporch
+ v_sync
+ rb_v_bporch
;
222 v_blank
= vbi_lines
< rb_min_vbi
? rb_min_vbi
: vbi_lines
;
223 double total_v_lines
= v_blank
+ v_lines_rnd
+ vert_margin
* 2 + interlace
;
224 if (rb
== RB_CVT_V3
&& early_vsync_rqd
) {
225 rb_v_bporch
= floor(vbi_lines
/ 2.0);
226 if (v_blank
- rb_v_bporch
- v_sync
< rb_v_fporch
)
227 rb_v_bporch
= v_blank
- v_sync
- rb_v_fporch
;
230 v_sync_bp
= v_blank
- rb_v_fporch
;
232 v_sync_bp
= v_sync
+ rb_v_bporch
;
233 double total_pixels
= h_blank
+ total_active_pixels
;
234 double freq
= v_field_rate_rqd
* total_v_lines
* total_pixels
* refresh_multiplier
;
236 pixel_freq
= ceil((freq
/ 1000000.0) / clock_step
) * clock_step
;
238 pixel_freq
= floor((freq
/ 1000000.0) / clock_step
) * clock_step
;
241 t
.vbp
= v_sync_bp
- v_sync
;
243 t
.vfp
= v_blank
- t
.vbp
- t
.vsync
;
244 t
.pixclk_khz
= round(1000.0 * pixel_freq
);
249 t
.hfp
= (h_blank
/ 2.0) - t
.hsync
;
250 t
.hbp
= h_blank
- t
.hfp
- t
.hsync
;
251 t
.hborder
= hor_margin
;
252 t
.vborder
= vert_margin
;
254 if (alt
&& (rb
== RB_CVT_V2
|| rb
== RB_CVT_V3
))
256 t
.pos_pol_hsync
= t
.rb
;
257 t
.pos_pol_vsync
= !t
.rb
;
262 void edid_state::edid_cvt_mode(unsigned refresh
, struct timings
&t
, unsigned rb_h_blank
,
263 unsigned rb_v_blank
, bool early_vsync_rqd
)
265 unsigned hratio
= t
.hratio
;
266 unsigned vratio
= t
.vratio
;
268 t
= calc_cvt_mode(t
.hact
, t
.vact
, refresh
, t
.rb
& ~RB_ALT
, t
.interlaced
,
269 false, t
.rb
& RB_ALT
, rb_h_blank
, rb_v_blank
, early_vsync_rqd
);