2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
6 /* Generate mode timings using the GTF Timing Standard
8 * Copyright (c) 2001, Andy Ritger aritger@nvidia.com
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * o Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * o Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer
19 * in the documentation and/or other materials provided with the
21 * o Neither the name of NVIDIA nor the names of its contributors
22 * may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
28 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
30 * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
41 * This program is based on the Generalized Timing Formula(GTF TM)
42 * Standard Version: 1.0, Revision: 1.0
44 * The GTF Document contains the following Copyright information:
46 * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards
47 * Association. Duplication of this document within VESA member
48 * companies for review purposes is permitted. All other rights
51 * While every precaution has been taken in the preparation
52 * of this standard, the Video Electronics Standards Association and
53 * its contributors assume no responsibility for errors or omissions,
54 * and make no warranties, expressed or implied, of functionality
55 * of suitability for any purpose. The sample code contained within
56 * this standard may be used without restriction.
60 * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive)
61 * implementation of the GTF Timing Standard, is available at:
63 * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls
67 * This program takes a desired resolution and vertical refresh rate,
68 * and computes mode timings according to the GTF Timing Standard.
69 * These mode timings can then be formatted as an XFree86 modeline
70 * or a mode description for use by fbset(8).
74 * The GTF allows for computation of "margins" (the visible border
75 * surrounding the addressable video); on most non-overscan type
76 * systems, the margin period is zero. I've implemented the margin
77 * computations but not enabled it because 1) I don't really have
78 * any experience with this, and 2) neither XFree86 modelines nor
79 * fbset fb.modes provide an obvious way for margin timings to be
80 * included in their mode descriptions (needs more investigation).
82 * The GTF provides for computation of interlaced mode timings;
83 * I've implemented the computations but not enabled them, yet.
84 * I should probably enable and test this at some point.
88 * o Add support for interlaced modes.
90 * o Implement the other portions of the GTF: compute mode timings
91 * given either the desired pixel clock or the desired horizontal
94 * o It would be nice if this were more general purpose to do things
95 * outside the scope of the GTF: like generate double scan mode
96 * timings, for example.
103 #include <compute_display_timing.h>
109 //#define TRACE_COMPUTE
111 # define TRACE(x, ...) debug_printf(x, __VA_ARGS__)
113 # define TRACE(x, ...) ;
117 #define MARGIN_PERCENT 1.8 // % of active vertical image
118 #define CELL_GRANULARITY 8.0
119 // assumed character cell granularity
120 #define MIN_PORCH 1 // minimum front porch
121 #define V_SYNC_WIDTH 3 // width of vsync in lines
122 #define H_SYNC_PERCENT 8.0 // width of hsync as % of total line
123 #define MIN_VSYNC_PLUS_BACK_PORCH 550.0 // time in microsec
125 // C' and M' are part of the Blanking Duty Cycle computation
127 #define M 600.0 // blanking formula gradient
128 #define C 40.0 // blanking formula offset
129 #define K 128.0 // blanking formula scaling factor
130 #define J 20.0 // blanking formula scaling factor
131 #define C_PRIME (((C - J) * K / 256.0) + J)
132 #define M_PRIME (K / 256.0 * M)
135 /*! As defined by the GTF Timing Standard, compute the Stage 1 Parameters
136 using the vertical refresh frequency. In other words: input a desired
137 resolution and desired refresh rate, and output the GTF mode timings.
140 compute_display_timing(uint32 width
, uint32 height
, float refresh
,
141 bool interlaced
, display_timing
* timing
)
143 if (width
< 320 || height
< 200 || width
> 65536 || height
> 65536
144 || refresh
< 25 || refresh
> 1000)
147 bool margins
= false;
149 // 1. In order to give correct results, the number of horizontal
150 // pixels requested is first processed to ensure that it is divisible
151 // by the character size, by rounding it to the nearest character
153 // [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
154 width
= (uint32
)(rint(width
/ CELL_GRANULARITY
) * CELL_GRANULARITY
);
156 // 2. If interlace is requested, the number of vertical lines assumed
157 // by the calculation must be halved, as the computation calculates
158 // the number of vertical lines per field. In either case, the
159 // number of lines is rounded to the nearest integer.
160 // [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
161 // ROUND([V LINES],0))
162 float verticalLines
= interlaced
? (double)height
/ 2.0 : (double)height
;
164 // 3. Find the frame rate required:
165 // [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
167 float verticalFieldRate
= interlaced
? refresh
* 2.0 : refresh
;
169 // 4. Find number of lines in Top margin:
170 // [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
171 // ROUND(([MARGIN%]/100*[V LINES RND]),0), 0)
172 float topMargin
= margins
? rint(MARGIN_PERCENT
/ 100.0 * verticalLines
)
175 // 5. Find number of lines in Bottom margin:
176 // [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
177 // ROUND(([MARGIN%]/100*[V LINES RND]),0), 0)
178 float bottomMargin
= margins
? rint(MARGIN_PERCENT
/ 100.0 * verticalLines
)
181 // 6. If interlace is required, then set variable [INTERLACE]=0.5:
182 // [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
183 float interlace
= interlaced
? 0.5 : 0.0;
185 // 7. Estimate the Horizontal period
186 // [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000)
187 // / ([V LINES RND] + (2*[TOP MARGIN (LINES)])
188 // + [MIN PORCH RND]+[INTERLACE]) * 1000000
189 float horizontalPeriodEstimate
= (1.0 / verticalFieldRate
190 - MIN_VSYNC_PLUS_BACK_PORCH
/ 1000000.0)
191 / (verticalLines
+ (2 * topMargin
) + MIN_PORCH
+ interlace
) * 1000000.0;
193 // 8. Find the number of lines in V sync + back porch:
194 // [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
195 float verticalSyncPlusBackPorch
= rint(MIN_VSYNC_PLUS_BACK_PORCH
196 / horizontalPeriodEstimate
);
198 // 10. Find the total number of lines in Vertical field period:
199 // [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)]
200 // + [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + [MIN PORCH RND]
201 float totalVerticalLines
= verticalLines
+ topMargin
+ bottomMargin
202 + verticalSyncPlusBackPorch
+ interlace
+ MIN_PORCH
;
204 // 11. Estimate the Vertical field frequency:
205 // [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
206 float verticalFieldRateEstimate
= 1.0 / horizontalPeriodEstimate
207 / totalVerticalLines
* 1000000.0;
209 // 12. Find the actual horizontal period:
210 // [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
211 float horizontalPeriod
= horizontalPeriodEstimate
212 / (verticalFieldRate
/ verticalFieldRateEstimate
);
214 // 15. Find number of pixels in left margin:
215 // [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
216 // (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
217 // [CELL GRAN RND]),0)) * [CELL GRAN RND], 0))
218 float leftMargin
= margins
? rint(width
* MARGIN_PERCENT
/ 100.0
219 / CELL_GRANULARITY
) * CELL_GRANULARITY
: 0.0;
221 // 16. Find number of pixels in right margin:
222 // [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
223 // (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
224 // [CELL GRAN RND]),0)) * [CELL GRAN RND], 0))
225 float rightMargin
= margins
? rint(width
* MARGIN_PERCENT
/ 100.0
226 / CELL_GRANULARITY
) * CELL_GRANULARITY
: 0.0;
228 // 17. Find total number of active pixels in image and left and right
230 // [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)]
231 // + [RIGHT MARGIN (PIXELS)]
232 float totalActivePixels
= width
+ leftMargin
+ rightMargin
;
234 // 18. Find the ideal blanking duty cycle from the blanking duty cycle
236 // [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
237 float idealDutyCycle
= C_PRIME
- (M_PRIME
* horizontalPeriod
/ 1000.0);
239 // 19. Find the number of pixels in the blanking time to the nearest
240 // double character cell:
241 // [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS]
242 // * [IDEAL DUTY CYCLE] / (100-[IDEAL DUTY CYCLE])
243 // / (2*[CELL GRAN RND])), 0)) * (2*[CELL GRAN RND])
244 float horizontalBlank
= rint(totalActivePixels
* idealDutyCycle
245 / (100.0 - idealDutyCycle
) / (2.0 * CELL_GRANULARITY
))
246 * (2.0 * CELL_GRANULARITY
);
248 // 20. Find total number of pixels:
249 // [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
250 float totalPixels
= totalActivePixels
+ horizontalBlank
;
252 // 21. Find pixel clock frequency:
253 // [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
254 float pixelFrequency
= totalPixels
/ horizontalPeriod
;
256 // Stage 1 computations are now complete; I should really pass
257 // the results to another function and do the Stage 2
258 // computations, but I only need a few more values so I'll just
259 // append the computations here for now */
261 // 17. Find the number of pixels in the horizontal sync period:
262 // [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS]
263 // / [CELL GRAN RND]),0))*[CELL GRAN RND]
264 float horizontalSync
= rint(H_SYNC_PERCENT
/ 100.0 * totalPixels
265 / CELL_GRANULARITY
) * CELL_GRANULARITY
;
267 // 18. Find the number of pixels in the horizontal front porch period:
268 // [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
269 float horizontalFrontPorch
= (horizontalBlank
/ 2.0) - horizontalSync
;
271 // 36. Find the number of lines in the odd front porch period:
272 // [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
273 float verticalOddFrontPorchLines
= MIN_PORCH
+ interlace
;
275 // finally, pack the results in the mode struct
277 timing
->pixel_clock
= uint32(pixelFrequency
* 1000);
278 timing
->h_display
= (uint16
)width
;
279 timing
->h_sync_start
= (uint16
)(width
+ horizontalFrontPorch
);
281 = (uint16
)(width
+ horizontalFrontPorch
+ horizontalSync
);
282 timing
->h_total
= (uint16
)totalPixels
;
283 timing
->v_display
= (uint16
)verticalLines
;
284 timing
->v_sync_start
= (uint16
)(verticalLines
+ verticalOddFrontPorchLines
);
286 = (uint16
)(verticalLines
+ verticalOddFrontPorchLines
+ V_SYNC_WIDTH
);
287 timing
->v_total
= (uint16
)totalVerticalLines
;
288 timing
->flags
= B_POSITIVE_HSYNC
| B_POSITIVE_VSYNC
289 | (interlace
? B_TIMING_INTERLACED
: 0);
291 TRACE("GTF TIMING: %lu kHz, (%u, %u, %u, %u), (%u, %u, %u, %u)\n",
292 timing
->pixel_clock
, timing
->h_display
, timing
->h_sync_start
,
293 timing
->h_sync_end
, timing
->h_total
, timing
->v_display
,
294 timing
->v_sync_start
, timing
->v_sync_end
, timing
->v_total
);