Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* gtf.c Generate mode timings using the GTF Timing Standard |
2 | * | |
3 | * gcc gtf.c -o gtf -lm -Wall | |
4 | * | |
5 | * Copyright (c) 2001, Andy Ritger aritger@nvidia.com | |
6 | * All rights reserved. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * o Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * o Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer | |
16 | * in the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * o Neither the name of NVIDIA nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this | |
20 | * software without specific prior written permission. | |
21 | * | |
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 | * | |
37 | * | |
38 | * This program is based on the Generalized Timing Formula(GTF TM) | |
39 | * Standard Version: 1.0, Revision: 1.0 | |
40 | * | |
41 | * The GTF Document contains the following Copyright information: | |
42 | * | |
43 | * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards | |
44 | * Association. Duplication of this document within VESA member | |
45 | * companies for review purposes is permitted. All other rights | |
46 | * reserved. | |
47 | * | |
48 | * While every precaution has been taken in the preparation | |
49 | * of this standard, the Video Electronics Standards Association and | |
50 | * its contributors assume no responsibility for errors or omissions, | |
51 | * and make no warranties, expressed or implied, of functionality | |
52 | * of suitability for any purpose. The sample code contained within | |
53 | * this standard may be used without restriction. | |
54 | * | |
55 | * | |
56 | * | |
57 | * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) | |
58 | * implementation of the GTF Timing Standard, is available at: | |
59 | * | |
60 | * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls | |
61 | * | |
62 | * | |
63 | * | |
64 | * This program takes a desired resolution and vertical refresh rate, | |
65 | * and computes mode timings according to the GTF Timing Standard. | |
66 | * These mode timings can then be formatted as an XServer modeline | |
67 | * or a mode description for use by fbset(8). | |
68 | * | |
69 | * | |
70 | * | |
71 | * NOTES: | |
72 | * | |
73 | * The GTF allows for computation of "margins" (the visible border | |
74 | * surrounding the addressable video); on most non-overscan type | |
75 | * systems, the margin period is zero. I've implemented the margin | |
76 | * computations but not enabled it because 1) I don't really have | |
77 | * any experience with this, and 2) neither XServer modelines nor | |
78 | * fbset fb.modes provide an obvious way for margin timings to be | |
79 | * included in their mode descriptions (needs more investigation). | |
80 | * | |
81 | * The GTF provides for computation of interlaced mode timings; | |
82 | * I've implemented the computations but not enabled them, yet. | |
83 | * I should probably enable and test this at some point. | |
84 | * | |
85 | * | |
86 | * | |
87 | * TODO: | |
88 | * | |
89 | * o Add support for interlaced modes. | |
90 | * | |
91 | * o Implement the other portions of the GTF: compute mode timings | |
92 | * given either the desired pixel clock or the desired horizontal | |
93 | * frequency. | |
94 | * | |
95 | * o It would be nice if this were more general purpose to do things | |
96 | * outside the scope of the GTF: like generate double scan mode | |
97 | * timings, for example. | |
98 | * | |
99 | * o Printing digits to the right of the decimal point when the | |
100 | * digits are 0 annoys me. | |
101 | * | |
102 | * o Error checking. | |
103 | * | |
104 | */ | |
105 | ||
106 | #ifdef HAVE_XORG_CONFIG_H | |
107 | #include <xorg-config.h> | |
108 | #endif | |
109 | ||
110 | #include <stdio.h> | |
111 | #include <stdlib.h> | |
112 | #include <string.h> | |
113 | #include <math.h> | |
114 | ||
115 | #define MARGIN_PERCENT 1.8 /* % of active vertical image */ | |
116 | #define CELL_GRAN 8.0 /* assumed character cell granularity */ | |
117 | #define MIN_PORCH 1 /* minimum front porch */ | |
118 | #define V_SYNC_RQD 3 /* width of vsync in lines */ | |
119 | #define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ | |
120 | #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */ | |
121 | #define M 600.0 /* blanking formula gradient */ | |
122 | #define C 40.0 /* blanking formula offset */ | |
123 | #define K 128.0 /* blanking formula scaling factor */ | |
124 | #define J 20.0 /* blanking formula scaling factor */ | |
125 | ||
126 | /* C' and M' are part of the Blanking Duty Cycle computation */ | |
127 | ||
128 | #define C_PRIME (((C - J) * K/256.0) + J) | |
129 | #define M_PRIME (K/256.0 * M) | |
130 | ||
131 | /* struct definitions */ | |
132 | ||
133 | typedef struct __mode { | |
134 | int hr, hss, hse, hfl; | |
135 | int vr, vss, vse, vfl; | |
136 | float pclk, h_freq, v_freq; | |
137 | } mode; | |
138 | ||
139 | typedef struct __options { | |
140 | int x, y; | |
141 | int xorgmode, fbmode; | |
142 | float v_freq; | |
143 | } options; | |
144 | ||
145 | /* prototypes */ | |
146 | ||
147 | void print_value(int n, const char *name, float val); | |
148 | void print_xf86_mode(mode * m); | |
149 | void print_fb_mode(mode * m); | |
150 | mode *vert_refresh(int h_pixels, int v_lines, float freq, | |
151 | int interlaced, int margins); | |
152 | options *parse_command_line(int argc, char *argv[]); | |
153 | ||
154 | /* | |
155 | * print_value() - print the result of the named computation; this is | |
156 | * useful when comparing against the GTF EXCEL spreadsheet. | |
157 | */ | |
158 | ||
159 | int global_verbose = 0; | |
160 | ||
161 | void | |
162 | print_value(int n, const char *name, float val) | |
163 | { | |
164 | if (global_verbose) { | |
165 | printf("%2d: %-27s: %15f\n", n, name, val); | |
166 | } | |
167 | } | |
168 | ||
169 | /* print_xf86_mode() - print the XServer modeline, given mode timings. */ | |
170 | ||
171 | void | |
172 | print_xf86_mode(mode * m) | |
173 | { | |
174 | printf("\n"); | |
175 | printf(" # %dx%d @ %.2f Hz (GTF) hsync: %.2f kHz; pclk: %.2f MHz\n", | |
176 | m->hr, m->vr, m->v_freq, m->h_freq, m->pclk); | |
177 | ||
178 | printf(" Modeline \"%dx%d_%.2f\" %.2f" | |
179 | " %d %d %d %d" | |
180 | " %d %d %d %d" | |
181 | " -HSync +Vsync\n\n", | |
182 | m->hr, m->vr, m->v_freq, m->pclk, | |
183 | m->hr, m->hss, m->hse, m->hfl, m->vr, m->vss, m->vse, m->vfl); | |
184 | ||
185 | } | |
186 | ||
187 | /* | |
188 | * print_fb_mode() - print a mode description in fbset(8) format; | |
189 | * see the fb.modes(8) manpage. The timing description used in | |
190 | * this is rather odd; they use "left and right margin" to refer | |
191 | * to the portion of the hblank before and after the sync pulse | |
192 | * by conceptually wrapping the portion of the blank after the pulse | |
193 | * to infront of the visible region; ie: | |
194 | * | |
195 | * | |
196 | * Timing description I'm accustomed to: | |
197 | * | |
198 | * | |
199 | * | |
200 | * <--------1--------> <--2--> <--3--> <--4--> | |
201 | * _________ | |
202 | * |-------------------|_______| |_______ | |
203 | * | |
204 | * R SS SE FL | |
205 | * | |
206 | * 1: visible image | |
207 | * 2: blank before sync (aka front porch) | |
208 | * 3: sync pulse | |
209 | * 4: blank after sync (aka back porch) | |
210 | * R: Resolution | |
211 | * SS: Sync Start | |
212 | * SE: Sync End | |
213 | * FL: Frame Length | |
214 | * | |
215 | * | |
216 | * But the fb.modes format is: | |
217 | * | |
218 | * | |
219 | * <--4--> <--------1--------> <--2--> <--3--> | |
220 | * _________ | |
221 | * _______|-------------------|_______| | | |
222 | * | |
223 | * The fb.modes(8) manpage refers to <4> and <2> as the left and | |
224 | * right "margin" (as well as upper and lower margin in the vertical | |
225 | * direction) -- note that this has nothing to do with the term | |
226 | * "margin" used in the GTF Timing Standard. | |
227 | * | |
228 | * XXX always prints the 32 bit mode -- should I provide a command | |
229 | * line option to specify the bpp? It's simple enough for a user | |
230 | * to edit the mode description after it's generated. | |
231 | */ | |
232 | ||
233 | void | |
234 | print_fb_mode(mode * m) | |
235 | { | |
236 | printf("\n"); | |
237 | printf("mode \"%dx%d %.2fHz 32bit (GTF)\"\n", m->hr, m->vr, m->v_freq); | |
238 | printf(" # PCLK: %.2f MHz, H: %.2f kHz, V: %.2f Hz\n", | |
239 | m->pclk, m->h_freq, m->v_freq); | |
240 | printf(" geometry %d %d %d %d 32\n", m->hr, m->vr, m->hr, m->vr); | |
241 | printf(" timings %d %d %d %d %d %d %d\n", (int) rint(1000000.0 / m->pclk), /* pixclock in picoseconds */ | |
242 | m->hfl - m->hse, /* left margin (in pixels) */ | |
243 | m->hss - m->hr, /* right margin (in pixels) */ | |
244 | m->vfl - m->vse, /* upper margin (in pixel lines) */ | |
245 | m->vss - m->vr, /* lower margin (in pixel lines) */ | |
246 | m->hse - m->hss, /* horizontal sync length (pixels) */ | |
247 | m->vse - m->vss); /* vert sync length (pixel lines) */ | |
248 | printf(" hsync low\n"); | |
249 | printf(" vsync high\n"); | |
250 | printf("endmode\n\n"); | |
251 | ||
252 | } | |
253 | ||
254 | /* | |
255 | * vert_refresh() - as defined by the GTF Timing Standard, compute the | |
256 | * Stage 1 Parameters using the vertical refresh frequency. In other | |
257 | * words: input a desired resolution and desired refresh rate, and | |
258 | * output the GTF mode timings. | |
259 | * | |
260 | * XXX All the code is in place to compute interlaced modes, but I don't | |
261 | * feel like testing it right now. | |
262 | * | |
263 | * XXX margin computations are implemented but not tested (nor used by | |
264 | * XServer of fbset mode descriptions, from what I can tell). | |
265 | */ | |
266 | ||
267 | mode * | |
268 | vert_refresh(int h_pixels, int v_lines, float freq, int interlaced, int margins) | |
269 | { | |
270 | float h_pixels_rnd; | |
271 | float v_lines_rnd; | |
272 | float v_field_rate_rqd; | |
273 | float top_margin; | |
274 | float bottom_margin; | |
275 | float interlace; | |
276 | float h_period_est; | |
277 | float vsync_plus_bp; | |
278 | float v_back_porch; | |
279 | float total_v_lines; | |
280 | float v_field_rate_est; | |
281 | float h_period; | |
282 | float v_field_rate; | |
283 | float v_frame_rate; | |
284 | float left_margin; | |
285 | float right_margin; | |
286 | float total_active_pixels; | |
287 | float ideal_duty_cycle; | |
288 | float h_blank; | |
289 | float total_pixels; | |
290 | float pixel_freq; | |
291 | float h_freq; | |
292 | ||
293 | float h_sync; | |
294 | float h_front_porch; | |
295 | float v_odd_front_porch_lines; | |
296 | ||
297 | mode *m = (mode *) malloc(sizeof(mode)); | |
298 | ||
299 | /* 1. In order to give correct results, the number of horizontal | |
300 | * pixels requested is first processed to ensure that it is divisible | |
301 | * by the character size, by rounding it to the nearest character | |
302 | * cell boundary: | |
303 | * | |
304 | * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) | |
305 | */ | |
306 | ||
307 | h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; | |
308 | ||
309 | print_value(1, "[H PIXELS RND]", h_pixels_rnd); | |
310 | ||
311 | /* 2. If interlace is requested, the number of vertical lines assumed | |
312 | * by the calculation must be halved, as the computation calculates | |
313 | * the number of vertical lines per field. In either case, the | |
314 | * number of lines is rounded to the nearest integer. | |
315 | * | |
316 | * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), | |
317 | * ROUND([V LINES],0)) | |
318 | */ | |
319 | ||
320 | v_lines_rnd = interlaced ? | |
321 | rint((float) v_lines) / 2.0 : rint((float) v_lines); | |
322 | ||
323 | print_value(2, "[V LINES RND]", v_lines_rnd); | |
324 | ||
325 | /* 3. Find the frame rate required: | |
326 | * | |
327 | * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, | |
328 | * [I/P FREQ RQD]) | |
329 | */ | |
330 | ||
331 | v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); | |
332 | ||
333 | print_value(3, "[V FIELD RATE RQD]", v_field_rate_rqd); | |
334 | ||
335 | /* 4. Find number of lines in Top margin: | |
336 | * | |
337 | * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", | |
338 | * ROUND(([MARGIN%]/100*[V LINES RND]),0), | |
339 | * 0) | |
340 | */ | |
341 | ||
342 | top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); | |
343 | ||
344 | print_value(4, "[TOP MARGIN (LINES)]", top_margin); | |
345 | ||
346 | /* 5. Find number of lines in Bottom margin: | |
347 | * | |
348 | * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", | |
349 | * ROUND(([MARGIN%]/100*[V LINES RND]),0), | |
350 | * 0) | |
351 | */ | |
352 | ||
353 | bottom_margin = | |
354 | margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); | |
355 | ||
356 | print_value(5, "[BOT MARGIN (LINES)]", bottom_margin); | |
357 | ||
358 | /* 6. If interlace is required, then set variable [INTERLACE]=0.5: | |
359 | * | |
360 | * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) | |
361 | */ | |
362 | ||
363 | interlace = interlaced ? 0.5 : 0.0; | |
364 | ||
365 | print_value(6, "[INTERLACE]", interlace); | |
366 | ||
367 | /* 7. Estimate the Horizontal period | |
368 | * | |
369 | * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / | |
370 | * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + | |
371 | * [MIN PORCH RND]+[INTERLACE]) * 1000000 | |
372 | */ | |
373 | ||
374 | h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) | |
375 | / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) | |
376 | * 1000000.0); | |
377 | ||
378 | print_value(7, "[H PERIOD EST]", h_period_est); | |
379 | ||
380 | /* 8. Find the number of lines in V sync + back porch: | |
381 | * | |
382 | * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) | |
383 | */ | |
384 | ||
385 | vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est); | |
386 | ||
387 | print_value(8, "[V SYNC+BP]", vsync_plus_bp); | |
388 | ||
389 | /* 9. Find the number of lines in V back porch alone: | |
390 | * | |
391 | * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] | |
392 | * | |
393 | * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? | |
394 | */ | |
395 | ||
396 | v_back_porch = vsync_plus_bp - V_SYNC_RQD; | |
397 | ||
398 | print_value(9, "[V BACK PORCH]", v_back_porch); | |
399 | ||
400 | /* 10. Find the total number of lines in Vertical field period: | |
401 | * | |
402 | * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + | |
403 | * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + | |
404 | * [MIN PORCH RND] | |
405 | */ | |
406 | ||
407 | total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + | |
408 | interlace + MIN_PORCH; | |
409 | ||
410 | print_value(10, "[TOTAL V LINES]", total_v_lines); | |
411 | ||
412 | /* 11. Estimate the Vertical field frequency: | |
413 | * | |
414 | * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 | |
415 | */ | |
416 | ||
417 | v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; | |
418 | ||
419 | print_value(11, "[V FIELD RATE EST]", v_field_rate_est); | |
420 | ||
421 | /* 12. Find the actual horizontal period: | |
422 | * | |
423 | * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) | |
424 | */ | |
425 | ||
426 | h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); | |
427 | ||
428 | print_value(12, "[H PERIOD]", h_period); | |
429 | ||
430 | /* 13. Find the actual Vertical field frequency: | |
431 | * | |
432 | * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 | |
433 | */ | |
434 | ||
435 | v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; | |
436 | ||
437 | print_value(13, "[V FIELD RATE]", v_field_rate); | |
438 | ||
439 | /* 14. Find the Vertical frame frequency: | |
440 | * | |
441 | * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) | |
442 | */ | |
443 | ||
444 | v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; | |
445 | ||
446 | print_value(14, "[V FRAME RATE]", v_frame_rate); | |
447 | ||
448 | /* 15. Find number of pixels in left margin: | |
449 | * | |
450 | * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", | |
451 | * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / | |
452 | * [CELL GRAN RND]),0)) * [CELL GRAN RND], | |
453 | * 0)) | |
454 | */ | |
455 | ||
456 | left_margin = margins ? | |
457 | rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : | |
458 | 0.0; | |
459 | ||
460 | print_value(15, "[LEFT MARGIN (PIXELS)]", left_margin); | |
461 | ||
462 | /* 16. Find number of pixels in right margin: | |
463 | * | |
464 | * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", | |
465 | * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / | |
466 | * [CELL GRAN RND]),0)) * [CELL GRAN RND], | |
467 | * 0)) | |
468 | */ | |
469 | ||
470 | right_margin = margins ? | |
471 | rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : | |
472 | 0.0; | |
473 | ||
474 | print_value(16, "[RIGHT MARGIN (PIXELS)]", right_margin); | |
475 | ||
476 | /* 17. Find total number of active pixels in image and left and right | |
477 | * margins: | |
478 | * | |
479 | * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + | |
480 | * [RIGHT MARGIN (PIXELS)] | |
481 | */ | |
482 | ||
483 | total_active_pixels = h_pixels_rnd + left_margin + right_margin; | |
484 | ||
485 | print_value(17, "[TOTAL ACTIVE PIXELS]", total_active_pixels); | |
486 | ||
487 | /* 18. Find the ideal blanking duty cycle from the blanking duty cycle | |
488 | * equation: | |
489 | * | |
490 | * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) | |
491 | */ | |
492 | ||
493 | ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); | |
494 | ||
495 | print_value(18, "[IDEAL DUTY CYCLE]", ideal_duty_cycle); | |
496 | ||
497 | /* 19. Find the number of pixels in the blanking time to the nearest | |
498 | * double character cell: | |
499 | * | |
500 | * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * | |
501 | * [IDEAL DUTY CYCLE] / | |
502 | * (100-[IDEAL DUTY CYCLE]) / | |
503 | * (2*[CELL GRAN RND])), 0)) | |
504 | * * (2*[CELL GRAN RND]) | |
505 | */ | |
506 | ||
507 | h_blank = rint(total_active_pixels * | |
508 | ideal_duty_cycle / | |
509 | (100.0 - ideal_duty_cycle) / | |
510 | (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); | |
511 | ||
512 | print_value(19, "[H BLANK (PIXELS)]", h_blank); | |
513 | ||
514 | /* 20. Find total number of pixels: | |
515 | * | |
516 | * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] | |
517 | */ | |
518 | ||
519 | total_pixels = total_active_pixels + h_blank; | |
520 | ||
521 | print_value(20, "[TOTAL PIXELS]", total_pixels); | |
522 | ||
523 | /* 21. Find pixel clock frequency: | |
524 | * | |
525 | * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] | |
526 | */ | |
527 | ||
528 | pixel_freq = total_pixels / h_period; | |
529 | ||
530 | print_value(21, "[PIXEL FREQ]", pixel_freq); | |
531 | ||
532 | /* 22. Find horizontal frequency: | |
533 | * | |
534 | * [H FREQ] = 1000 / [H PERIOD] | |
535 | */ | |
536 | ||
537 | h_freq = 1000.0 / h_period; | |
538 | ||
539 | print_value(22, "[H FREQ]", h_freq); | |
540 | ||
541 | /* Stage 1 computations are now complete; I should really pass | |
542 | the results to another function and do the Stage 2 | |
543 | computations, but I only need a few more values so I'll just | |
544 | append the computations here for now */ | |
545 | ||
546 | /* 17. Find the number of pixels in the horizontal sync period: | |
547 | * | |
548 | * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / | |
549 | * [CELL GRAN RND]),0))*[CELL GRAN RND] | |
550 | */ | |
551 | ||
552 | h_sync = | |
553 | rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; | |
554 | ||
555 | print_value(17, "[H SYNC (PIXELS)]", h_sync); | |
556 | ||
557 | /* 18. Find the number of pixels in the horizontal front porch period: | |
558 | * | |
559 | * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] | |
560 | */ | |
561 | ||
562 | h_front_porch = (h_blank / 2.0) - h_sync; | |
563 | ||
564 | print_value(18, "[H FRONT PORCH (PIXELS)]", h_front_porch); | |
565 | ||
566 | /* 36. Find the number of lines in the odd front porch period: | |
567 | * | |
568 | * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) | |
569 | */ | |
570 | ||
571 | v_odd_front_porch_lines = MIN_PORCH + interlace; | |
572 | ||
573 | print_value(36, "[V ODD FRONT PORCH(LINES)]", v_odd_front_porch_lines); | |
574 | ||
575 | /* finally, pack the results in the mode struct */ | |
576 | ||
577 | m->hr = (int) (h_pixels_rnd); | |
578 | m->hss = (int) (h_pixels_rnd + h_front_porch); | |
579 | m->hse = (int) (h_pixels_rnd + h_front_porch + h_sync); | |
580 | m->hfl = (int) (total_pixels); | |
581 | ||
582 | m->vr = (int) (v_lines_rnd); | |
583 | m->vss = (int) (v_lines_rnd + v_odd_front_porch_lines); | |
584 | m->vse = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); | |
585 | m->vfl = (int) (total_v_lines); | |
586 | ||
587 | m->pclk = pixel_freq; | |
588 | m->h_freq = h_freq; | |
589 | m->v_freq = freq; | |
590 | ||
591 | return m; | |
592 | ||
593 | } | |
594 | ||
595 | /* | |
596 | * parse_command_line() - parse the command line and return an | |
597 | * alloced structure containing the results. On error print usage | |
598 | * and return NULL. | |
599 | */ | |
600 | ||
601 | options * | |
602 | parse_command_line(int argc, char *argv[]) | |
603 | { | |
604 | int n; | |
605 | ||
606 | options *o = (options *) calloc(1, sizeof(options)); | |
607 | ||
608 | if (argc < 4) | |
609 | goto bad_option; | |
610 | ||
611 | o->x = atoi(argv[1]); | |
612 | o->y = atoi(argv[2]); | |
613 | o->v_freq = atof(argv[3]); | |
614 | ||
615 | /* XXX should check for errors in the above */ | |
616 | ||
617 | n = 4; | |
618 | ||
619 | while (n < argc) { | |
620 | if ((strcmp(argv[n], "-v") == 0) || (strcmp(argv[n], "--verbose") == 0)) { | |
621 | global_verbose = 1; | |
622 | } | |
623 | else if ((strcmp(argv[n], "-f") == 0) || | |
624 | (strcmp(argv[n], "--fbmode") == 0)) { | |
625 | o->fbmode = 1; | |
626 | } | |
627 | else if ((strcmp(argv[n], "-x") == 0) || | |
628 | (strcmp(argv[n], "--xorgmode") == 0) || | |
629 | (strcmp(argv[n], "--xf86mode") == 0)) { | |
630 | o->xorgmode = 1; | |
631 | } | |
632 | else { | |
633 | goto bad_option; | |
634 | } | |
635 | ||
636 | n++; | |
637 | } | |
638 | ||
639 | /* if neither xorgmode nor fbmode were requested, default to | |
640 | xorgmode */ | |
641 | ||
642 | if (!o->fbmode && !o->xorgmode) | |
643 | o->xorgmode = 1; | |
644 | ||
645 | return o; | |
646 | ||
647 | bad_option: | |
648 | ||
649 | fprintf(stderr, "\n"); | |
650 | fprintf(stderr, "usage: %s x y refresh [-v|--verbose] " | |
651 | "[-f|--fbmode] [-x|--xorgmode]\n", argv[0]); | |
652 | ||
653 | fprintf(stderr, "\n"); | |
654 | ||
655 | fprintf(stderr, " x : the desired horizontal " | |
656 | "resolution (required)\n"); | |
657 | fprintf(stderr, " y : the desired vertical " | |
658 | "resolution (required)\n"); | |
659 | fprintf(stderr, " refresh : the desired refresh " "rate (required)\n"); | |
660 | fprintf(stderr, " -v|--verbose : enable verbose printouts " | |
661 | "(traces each step of the computation)\n"); | |
662 | fprintf(stderr, " -f|--fbmode : output an fbset(8)-style mode " | |
663 | "description\n"); | |
664 | fprintf(stderr, " -x|--xorgmode : output an " __XSERVERNAME__ "-style mode " | |
665 | "description (this is the default\n" | |
666 | " if no mode description is requested)\n"); | |
667 | ||
668 | fprintf(stderr, "\n"); | |
669 | ||
670 | free(o); | |
671 | return NULL; | |
672 | ||
673 | } | |
674 | ||
675 | int | |
676 | main(int argc, char *argv[]) | |
677 | { | |
678 | mode *m; | |
679 | options *o; | |
680 | ||
681 | o = parse_command_line(argc, argv); | |
682 | if (!o) | |
683 | exit(1); | |
684 | ||
685 | m = vert_refresh(o->x, o->y, o->v_freq, 0, 0); | |
686 | if (!m) | |
687 | exit(1); | |
688 | ||
689 | if (o->xorgmode) | |
690 | print_xf86_mode(m); | |
691 | ||
692 | if (o->fbmode) | |
693 | print_fb_mode(m); | |
694 | ||
695 | return 0; | |
696 | ||
697 | } |