Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * gtf.c Generate mode timings using the GTF Timing Standard | |
3 | * | |
4 | * gcc gtf.c -o gtf -lm -Wall | |
5 | * | |
6 | * Copyright (c) 2001, Andy Ritger aritger@nvidia.com | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * o Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * o Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer | |
17 | * in the documentation and/or other materials provided with the | |
18 | * distribution. | |
19 | * o Neither the name of NVIDIA nor the names of its contributors | |
20 | * may be used to endorse or promote products derived from this | |
21 | * software without specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT | |
25 | * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
26 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
27 | * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
28 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
33 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
34 | * POSSIBILITY OF SUCH DAMAGE. | |
35 | * | |
36 | * This program is based on the Generalized Timing Formula(GTF TM) | |
37 | * Standard Version: 1.0, Revision: 1.0 | |
38 | * | |
39 | * The GTF Document contains the following Copyright information: | |
40 | * | |
41 | * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards | |
42 | * Association. Duplication of this document within VESA member | |
43 | * companies for review purposes is permitted. All other rights | |
44 | * reserved. | |
45 | * | |
46 | * While every precaution has been taken in the preparation | |
47 | * of this standard, the Video Electronics Standards Association and | |
48 | * its contributors assume no responsibility for errors or omissions, | |
49 | * and make no warranties, expressed or implied, of functionality | |
50 | * of suitability for any purpose. The sample code contained within | |
51 | * this standard may be used without restriction. | |
52 | * | |
53 | * | |
54 | * | |
55 | * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) | |
56 | * implementation of the GTF Timing Standard, is available at: | |
57 | * | |
58 | * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls | |
59 | */ | |
60 | ||
61 | /* Ruthlessly converted to server code by Adam Jackson <ajax@redhat.com> */ | |
62 | ||
63 | #ifdef HAVE_XORG_CONFIG_H | |
64 | #include <xorg-config.h> | |
65 | #else | |
66 | #ifdef HAVE_CONFIG_H | |
67 | #include <config.h> | |
68 | #endif | |
69 | #endif | |
70 | ||
71 | #include "xf86.h" | |
72 | #include "xf86Modes.h" | |
73 | #include <string.h> | |
74 | ||
75 | #define MARGIN_PERCENT 1.8 /* % of active vertical image */ | |
76 | #define CELL_GRAN 8.0 /* assumed character cell granularity */ | |
77 | #define MIN_PORCH 1 /* minimum front porch */ | |
78 | #define V_SYNC_RQD 3 /* width of vsync in lines */ | |
79 | #define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ | |
80 | #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */ | |
81 | #define M 600.0 /* blanking formula gradient */ | |
82 | #define C 40.0 /* blanking formula offset */ | |
83 | #define K 128.0 /* blanking formula scaling factor */ | |
84 | #define J 20.0 /* blanking formula scaling factor */ | |
85 | ||
86 | /* C' and M' are part of the Blanking Duty Cycle computation */ | |
87 | ||
88 | #define C_PRIME (((C - J) * K/256.0) + J) | |
89 | #define M_PRIME (K/256.0 * M) | |
90 | ||
91 | /* | |
92 | * xf86GTFMode() - as defined by the GTF Timing Standard, compute the | |
93 | * Stage 1 Parameters using the vertical refresh frequency. In other | |
94 | * words: input a desired resolution and desired refresh rate, and | |
95 | * output the GTF mode timings. | |
96 | * | |
97 | * XXX All the code is in place to compute interlaced modes, but I don't | |
98 | * feel like testing it right now. | |
99 | * | |
100 | * XXX margin computations are implemented but not tested (nor used by | |
101 | * XServer of fbset mode descriptions, from what I can tell). | |
102 | */ | |
103 | ||
104 | DisplayModePtr | |
105 | xf86GTFMode(int h_pixels, int v_lines, float freq, int interlaced, int margins) | |
106 | { | |
107 | DisplayModeRec *mode = xnfcalloc(1, sizeof(DisplayModeRec)); | |
108 | ||
109 | float h_pixels_rnd; | |
110 | float v_lines_rnd; | |
111 | float v_field_rate_rqd; | |
112 | float top_margin; | |
113 | float bottom_margin; | |
114 | float interlace; | |
115 | float h_period_est; | |
116 | float vsync_plus_bp; | |
117 | float v_back_porch; | |
118 | float total_v_lines; | |
119 | float v_field_rate_est; | |
120 | float h_period; | |
121 | float v_field_rate; | |
122 | float v_frame_rate; | |
123 | float left_margin; | |
124 | float right_margin; | |
125 | float total_active_pixels; | |
126 | float ideal_duty_cycle; | |
127 | float h_blank; | |
128 | float total_pixels; | |
129 | float pixel_freq; | |
130 | float h_freq; | |
131 | ||
132 | float h_sync; | |
133 | float h_front_porch; | |
134 | float v_odd_front_porch_lines; | |
135 | ||
136 | /* 1. In order to give correct results, the number of horizontal | |
137 | * pixels requested is first processed to ensure that it is divisible | |
138 | * by the character size, by rounding it to the nearest character | |
139 | * cell boundary: | |
140 | * | |
141 | * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) | |
142 | */ | |
143 | ||
144 | h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; | |
145 | ||
146 | /* 2. If interlace is requested, the number of vertical lines assumed | |
147 | * by the calculation must be halved, as the computation calculates | |
148 | * the number of vertical lines per field. In either case, the | |
149 | * number of lines is rounded to the nearest integer. | |
150 | * | |
151 | * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), | |
152 | * ROUND([V LINES],0)) | |
153 | */ | |
154 | ||
155 | v_lines_rnd = interlaced ? | |
156 | rint((float) v_lines) / 2.0 : rint((float) v_lines); | |
157 | ||
158 | /* 3. Find the frame rate required: | |
159 | * | |
160 | * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, | |
161 | * [I/P FREQ RQD]) | |
162 | */ | |
163 | ||
164 | v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); | |
165 | ||
166 | /* 4. Find number of lines in Top margin: | |
167 | * | |
168 | * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", | |
169 | * ROUND(([MARGIN%]/100*[V LINES RND]),0), | |
170 | * 0) | |
171 | */ | |
172 | ||
173 | top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); | |
174 | ||
175 | /* 5. Find number of lines in Bottom margin: | |
176 | * | |
177 | * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", | |
178 | * ROUND(([MARGIN%]/100*[V LINES RND]),0), | |
179 | * 0) | |
180 | */ | |
181 | ||
182 | bottom_margin = | |
183 | margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); | |
184 | ||
185 | /* 6. If interlace is required, then set variable [INTERLACE]=0.5: | |
186 | * | |
187 | * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) | |
188 | */ | |
189 | ||
190 | interlace = interlaced ? 0.5 : 0.0; | |
191 | ||
192 | /* 7. Estimate the Horizontal period | |
193 | * | |
194 | * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / | |
195 | * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + | |
196 | * [MIN PORCH RND]+[INTERLACE]) * 1000000 | |
197 | */ | |
198 | ||
199 | h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) | |
200 | / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) | |
201 | * 1000000.0); | |
202 | ||
203 | /* 8. Find the number of lines in V sync + back porch: | |
204 | * | |
205 | * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) | |
206 | */ | |
207 | ||
208 | vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est); | |
209 | ||
210 | /* 9. Find the number of lines in V back porch alone: | |
211 | * | |
212 | * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] | |
213 | * | |
214 | * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? | |
215 | */ | |
216 | ||
217 | v_back_porch = vsync_plus_bp - V_SYNC_RQD; | |
218 | ||
219 | /* 10. Find the total number of lines in Vertical field period: | |
220 | * | |
221 | * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + | |
222 | * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + | |
223 | * [MIN PORCH RND] | |
224 | */ | |
225 | ||
226 | total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + | |
227 | interlace + MIN_PORCH; | |
228 | ||
229 | /* 11. Estimate the Vertical field frequency: | |
230 | * | |
231 | * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 | |
232 | */ | |
233 | ||
234 | v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; | |
235 | ||
236 | /* 12. Find the actual horizontal period: | |
237 | * | |
238 | * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) | |
239 | */ | |
240 | ||
241 | h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); | |
242 | ||
243 | /* 13. Find the actual Vertical field frequency: | |
244 | * | |
245 | * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 | |
246 | */ | |
247 | ||
248 | v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; | |
249 | ||
250 | /* 14. Find the Vertical frame frequency: | |
251 | * | |
252 | * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) | |
253 | */ | |
254 | ||
255 | v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; | |
256 | ||
257 | /* 15. Find number of pixels in left margin: | |
258 | * | |
259 | * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", | |
260 | * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / | |
261 | * [CELL GRAN RND]),0)) * [CELL GRAN RND], | |
262 | * 0)) | |
263 | */ | |
264 | ||
265 | left_margin = margins ? | |
266 | rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : | |
267 | 0.0; | |
268 | ||
269 | /* 16. Find number of pixels in right margin: | |
270 | * | |
271 | * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", | |
272 | * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / | |
273 | * [CELL GRAN RND]),0)) * [CELL GRAN RND], | |
274 | * 0)) | |
275 | */ | |
276 | ||
277 | right_margin = margins ? | |
278 | rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : | |
279 | 0.0; | |
280 | ||
281 | /* 17. Find total number of active pixels in image and left and right | |
282 | * margins: | |
283 | * | |
284 | * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + | |
285 | * [RIGHT MARGIN (PIXELS)] | |
286 | */ | |
287 | ||
288 | total_active_pixels = h_pixels_rnd + left_margin + right_margin; | |
289 | ||
290 | /* 18. Find the ideal blanking duty cycle from the blanking duty cycle | |
291 | * equation: | |
292 | * | |
293 | * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) | |
294 | */ | |
295 | ||
296 | ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); | |
297 | ||
298 | /* 19. Find the number of pixels in the blanking time to the nearest | |
299 | * double character cell: | |
300 | * | |
301 | * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * | |
302 | * [IDEAL DUTY CYCLE] / | |
303 | * (100-[IDEAL DUTY CYCLE]) / | |
304 | * (2*[CELL GRAN RND])), 0)) | |
305 | * * (2*[CELL GRAN RND]) | |
306 | */ | |
307 | ||
308 | h_blank = rint(total_active_pixels * | |
309 | ideal_duty_cycle / | |
310 | (100.0 - ideal_duty_cycle) / | |
311 | (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); | |
312 | ||
313 | /* 20. Find total number of pixels: | |
314 | * | |
315 | * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] | |
316 | */ | |
317 | ||
318 | total_pixels = total_active_pixels + h_blank; | |
319 | ||
320 | /* 21. Find pixel clock frequency: | |
321 | * | |
322 | * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] | |
323 | */ | |
324 | ||
325 | pixel_freq = total_pixels / h_period; | |
326 | ||
327 | /* 22. Find horizontal frequency: | |
328 | * | |
329 | * [H FREQ] = 1000 / [H PERIOD] | |
330 | */ | |
331 | ||
332 | h_freq = 1000.0 / h_period; | |
333 | ||
334 | /* Stage 1 computations are now complete; I should really pass | |
335 | the results to another function and do the Stage 2 | |
336 | computations, but I only need a few more values so I'll just | |
337 | append the computations here for now */ | |
338 | ||
339 | /* 17. Find the number of pixels in the horizontal sync period: | |
340 | * | |
341 | * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / | |
342 | * [CELL GRAN RND]),0))*[CELL GRAN RND] | |
343 | */ | |
344 | ||
345 | h_sync = | |
346 | rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; | |
347 | ||
348 | /* 18. Find the number of pixels in the horizontal front porch period: | |
349 | * | |
350 | * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] | |
351 | */ | |
352 | ||
353 | h_front_porch = (h_blank / 2.0) - h_sync; | |
354 | ||
355 | /* 36. Find the number of lines in the odd front porch period: | |
356 | * | |
357 | * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) | |
358 | */ | |
359 | ||
360 | v_odd_front_porch_lines = MIN_PORCH + interlace; | |
361 | ||
362 | /* finally, pack the results in the mode struct */ | |
363 | ||
364 | mode->HDisplay = (int) (h_pixels_rnd); | |
365 | mode->HSyncStart = (int) (h_pixels_rnd + h_front_porch); | |
366 | mode->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync); | |
367 | mode->HTotal = (int) (total_pixels); | |
368 | mode->VDisplay = (int) (v_lines_rnd); | |
369 | mode->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines); | |
370 | mode->VSyncEnd = (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); | |
371 | mode->VTotal = (int) (total_v_lines); | |
372 | ||
373 | mode->Clock = (int) (pixel_freq * 1000.0); | |
374 | mode->HSync = h_freq; | |
375 | mode->VRefresh = freq; | |
376 | ||
377 | xf86SetModeDefaultName(mode); | |
378 | ||
379 | mode->Flags = V_NHSYNC | V_PVSYNC; | |
380 | if (interlaced) { | |
381 | mode->VTotal *= 2; | |
382 | mode->Flags |= V_INTERLACE; | |
383 | } | |
384 | ||
385 | return mode; | |
386 | } |