From 5747aa52485a0665c28bcf8c744d0b87162c0bbd Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Mon, 7 Mar 2005 09:35:49 +0000 Subject: cvt.c written using the xls file from vesa and based on gtf.c ; we don't use it at the moment, but it may be useful --- cvt.c | 585 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 cvt.c diff --git a/cvt.c b/cvt.c new file mode 100644 index 0000000..4773f34 --- /dev/null +++ b/cvt.c @@ -0,0 +1,585 @@ +/* cvt.c Generate mode timings using the CVT Standard + * + * gcc gtf.c -o gtf -lm -Wall + * + * Copyright (c) 2001, Andy Ritger aritger@nvidia.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * o Neither the name of NVIDIA nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * + * + * This program is based on the VESA Coordinated Video Timing(CVT TM) + * + * The CVT EXCEL(TM) SPREADSHEET, a sample + * implementation of the CVT Standard, is available at: + * + * http://www.vesa.org/Public/CVT/CVTd6r1.xls + * + * + * + * This program takes a desired resolution and vertical refresh rate, + * and computes mode timings according to the CVT Standard. + * These mode timings can then be formatted as an XServer modeline + * or a mode description for use by fbset(8). + * + * + * + * NOTES: + * + * The CVT allows for computation of "margins" (the visible border + * surrounding the addressable video); on most non-overscan type + * systems, the margin period is zero. I've implemented the margin + * computations but not enabled it because 1) I don't really have + * any experience with this, and 2) neither XServer modelines nor + * fbset fb.modes provide an obvious way for margin timings to be + * included in their mode descriptions (needs more investigation). + * + * The CVT provides for computation of interlaced mode timings; + * I've implemented the computations but not enabled them, yet. + * I should probably enable and test this at some point. + * + */ + +#include +#include +#include +#include + +#ifndef __XSERVERNAME__ +#define __XSERVERNAME__ "Xorg" +#endif +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#ifdef DEBUG +#define debug_printf(s) printf s +#else +#define debug_printf(s) +#endif + + +#define K93 1.8 +#define CELL_GRAN 8.0 /* assumed character cell granularity */ + +#define K104 8 + +#define K110 550.0 +#define MIN_V_BPORCH 6 +#define MIN_V_PORCH 3 /* width of vsync in lines */ + +#define GTF_M_VAR 600.0 /* blanking formula gradient */ +#define GTF_C_VAR 40.0 /* blanking formula offset */ +#define GTF_K_VAR 128.0 /* blanking formula scaling factor */ +#define GTF_J_VAR 20.0 /* blanking formula scaling factor */ + + +#define C_PRIME (((GTF_C_VAR - GTF_J_VAR) * GTF_K_VAR/256.0) + GTF_J_VAR) +#define M_PRIME (GTF_K_VAR/256.0 * GTF_M_VAR) + +/* C' and M' are part of the Blanking Duty Cycle computation */ + +/* reduced blanking vars */ +#define K130 160 +#define K131 32 +#define K133 460 +#define RB_V_FPORCH 3 +#define RB_MIN_V_FPORCH 6 + +#define CLOCK_STEP 0.25 + + +#define CELL_GRAN_RND floor(CELL_GRAN) +#define MARGIN_PER K93 +#define MIN_V_PORCH_RND floor(MIN_V_PORCH) + +#define MIN_VSYNC_BP K110 +#define H_SYNC_PER K104 + +#define RB_MIN_V_BLANK K133 +#define RB_H_SYNC K131 +#define RB_H_BLANK K130 +#define Y19 RB_H_SYNC +#define Y20 RB_H_BLANK + +/* struct definitions */ + +typedef struct __mode +{ + int hr, hss, hse, hfl; + int vr, vss, vse, vfl; + float pclk, h_freq, v_freq; + int reduced_blanking; +} mode; + + +typedef struct __options +{ + int x, y; + int xorgmode, fbmode, reduced_blanking; + float v_freq; +} options; + + + + +/* prototypes */ + +void print_value(int n, char *name, float val); +void print_xf86_mode (mode *m); +void print_fb_mode (mode *m); +options *parse_command_line (int argc, char *argv[]); + +const char *aspect_ratio(int width, int height, int *vsync_width) +{ + struct { + float val; + const char *name; + int vsync_width; + } ratios[] = { + { 4./ 3, "4:3", 4 }, + { 16./ 9, "16:9", 5 }, + { 16./10, "16:10", 6 }, + { 5./ 4, "5:4", 7 }, + { 15./ 9, "15:9", 7 }, + { 0, "", 10 }, + }; + int i; + for (i = 0; ratios[i].val; i++) + if (width == CELL_GRAN_RND * floor(height * ratios[i].val / CELL_GRAN_RND)) + break; + + if (vsync_width) *vsync_width = ratios[i].vsync_width; + return ratios[i].name; +} + +/* + * print_value() - print the result of the named computation; this is + * useful when comparing against the CVT EXCEL spreadsheet. + */ + +int global_verbose = 0; + +void print_value(int n, char *name, float val) +{ + if (global_verbose) { + printf("%2d: %-27s: %15f\n", n, name, val); + } +} + + + +/* print_xf86_mode() - print the XServer modeline, given mode timings. */ + +void print_xf86_mode (mode *m) +{ + printf ("\n"); + printf (" # %dx%d @ %.2f Hz (CVT%s) hsync: %.2f kHz; pclk: %.2f MHz\n", + m->hr, m->vr, m->v_freq, + m->reduced_blanking ? " - Reduced Blanking" : "", + m->h_freq, m->pclk); + + printf (" Modeline \"%dx%d_%.2f\" %.2f" + " %d %d %d %d" + " %d %d %d %d" + " -HSync +Vsync\n\n", + m->hr, m->vr, m->v_freq, m->pclk, + m->hr, m->hss, m->hse, m->hfl, + m->vr, m->vss, m->vse, m->vfl); + +} + + + +/* + * print_fb_mode() - print a mode description in fbset(8) format; + * see the fb.modes(8) manpage. The timing description used in + * this is rather odd; they use "left and right margin" to refer + * to the portion of the hblank before and after the sync pulse + * by conceptually wrapping the portion of the blank after the pulse + * to infront of the visible region; ie: + * + * + * Timing description I'm accustomed to: + * + * + * + * <--------1--------> <--2--> <--3--> <--4--> + * _________ + * |-------------------|_______| |_______ + * + * R SS SE FL + * + * 1: visible image + * 2: blank before sync (aka front porch) + * 3: sync pulse + * 4: blank after sync (aka back porch) + * R: Resolution + * SS: Sync Start + * SE: Sync End + * FL: Frame Length + * + * + * But the fb.modes format is: + * + * + * <--4--> <--------1--------> <--2--> <--3--> + * _________ + * _______|-------------------|_______| | + * + * The fb.modes(8) manpage refers to <4> and <2> as the left and + * right "margin" (as well as upper and lower margin in the vertical + * direction) -- note that this has nothing to do with the term + * "margin" used in the CVT Standard. + * + * XXX always prints the 32 bit mode -- should I provide a command + * line option to specify the bpp? It's simple enough for a user + * to edit the mode description after it's generated. + */ + +void print_fb_mode (mode *m) +{ + printf ("\n"); + printf ("mode \"%dx%d %.2fHz 32bit (CVT%s)\"\n", + m->hr, m->vr, m->v_freq, + m->reduced_blanking ? " - Reduced Blanking" : "" + ); + printf (" # PCLK: %.2f MHz, H: %.2f kHz, V: %.2f Hz\n", + m->pclk, m->h_freq, m->v_freq); + printf (" geometry %d %d %d %d 32\n", + m->hr, m->vr, m->hr, m->vr); + printf (" timings %d %d %d %d %d %d %d\n", + (int) floor(1000000.0/m->pclk),/* pixclock in picoseconds */ + m->hfl - m->hse, /* left margin (in pixels) */ + m->hss - m->hr, /* right margin (in pixels) */ + m->vfl - m->vse, /* upper margin (in pixel lines) */ + m->vss - m->vr, /* lower margin (in pixel lines) */ + m->hse - m->hss, /* horizontal sync length (pixels) */ + m->vse - m->vss); /* vert sync length (pixel lines) */ + printf (" hsync low\n"); + printf (" vsync high\n"); + printf ("endmode\n\n"); + +} + + + + +/* + * vert_refresh() - as defined by the CVT Standard, compute the + * Stage 1 Parameters using the vertical refresh frequency. In other + * words: input a desired resolution and desired refresh rate, and + * output the CVT mode timings. + * + * XXX All the code is in place to compute interlaced modes, but I don't + * feel like testing it right now. + * + * XXX margin computations are implemented but not tested (nor used by + * XServer of fbset mode descriptions, from what I can tell). + */ + +mode vert_refresh(int H_PIXELS, int V_LINES, float IP_FREQ_RQD, int RED_BLANK_RQD, int INT_RQD, int MARGINS_RQD) +{ + /* 1 */ + float V_FIELD_RATE_RQD = INT_RQD ? IP_FREQ_RQD * 2 : IP_FREQ_RQD; + + /* 2 */ + int H_PIXELS_RND = floor((float) H_PIXELS / CELL_GRAN_RND) * CELL_GRAN_RND; + int F39 = H_PIXELS_RND; + + /* 3 */ + int LEFT_MARGIN = MARGINS_RQD ? floor(H_PIXELS_RND * MARGIN_PER / 100 / CELL_GRAN_RND) * CELL_GRAN_RND : 0; + int RIGHT_MARGIN = LEFT_MARGIN; + + /* 4 */ + int TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + LEFT_MARGIN + RIGHT_MARGIN; + + debug_printf(("4: %d\n", TOTAL_ACTIVE_PIXELS)); + + /* 5 */ + int V_LINES_RND = floor(INT_RQD ? V_LINES / 2 : V_LINES); + int F40 = V_LINES; + + int V_SYNC; + /*const char *ASPECT_RATIO =*/ aspect_ratio(F39, F40, &V_SYNC); + int V_SYNC_RND = V_SYNC; + /*int Q76 = V_SYNC_RND;*/ + + debug_printf(("5: %d %d\n", V_LINES_RND, V_SYNC)); + + /* 6 */ + int TOP_MARGIN = MARGINS_RQD ? floor(MARGIN_PER / 100 * V_LINES_RND) : 0; + int BOT_MARGIN = TOP_MARGIN; + + debug_printf(("6: %d\n", TOP_MARGIN)); + + /* 7 */ + float INTERLACE = INT_RQD ? 0.5 : 0; + + /* 8 */ + float U23 = (1. / V_FIELD_RATE_RQD - MIN_VSYNC_BP / 1000000.) + / (V_LINES_RND + 2 * TOP_MARGIN + MIN_V_PORCH_RND + INTERLACE) + * 1000000; + + float Y23 = (1000000 / V_FIELD_RATE_RQD - RB_MIN_V_BLANK) / (V_LINES_RND + TOP_MARGIN + BOT_MARGIN); + + float H_PERIOD_EST = RED_BLANK_RQD ? Y23 : U23; + + debug_printf(("8: %f %f %f\n", U23, Y23, H_PERIOD_EST)); + + /* 9 */ + int U26 = floor(MIN_VSYNC_BP / H_PERIOD_EST) + 1; + /*float U27 = MIN_VSYNC_BP / H_PERIOD_EST;*/ + int V_SYNC_BP = U26 < V_SYNC + MIN_V_BPORCH ? V_SYNC + MIN_V_BPORCH : U26; + + debug_printf(("9: %d %d\n", U26, V_SYNC_BP)); + + /* 9' */ + int VBI_LINES = floor(RB_MIN_V_BLANK / H_PERIOD_EST) + 1; + /*float Y27 = RB_MIN_V_BLANK / H_PERIOD_EST;*/ + + debug_printf(("9': %d\n", VBI_LINES)); + + /* 10 */ + /*int U31 = V_SYNC_BP - V_SYNC_RND;*/ + + /* 10' */ + int RB_MIN_VBI = RB_V_FPORCH + V_SYNC_RND + MIN_V_BPORCH; + int ACT_VBI_LINES = VBI_LINES < RB_MIN_VBI ? RB_MIN_VBI : VBI_LINES; + + debug_printf(("10': %d %d\n", RB_MIN_VBI, ACT_VBI_LINES)); + + /* 11 */ + int U34 = V_LINES_RND + TOP_MARGIN + BOT_MARGIN + V_SYNC_BP + INTERLACE + MIN_V_PORCH_RND; + + debug_printf(("11: %d\n", U34)); + + /* 11' */ + int Y34 = ACT_VBI_LINES + V_LINES_RND + TOP_MARGIN + BOT_MARGIN + INTERLACE; + int TOTAL_V_LINES = RED_BLANK_RQD ? Y34 : U34; + + debug_printf(("11': %d %d\n", Y34, TOTAL_V_LINES)); + + /* 12 */ + float H_PERIOD = C_PRIME - M_PRIME*H_PERIOD_EST/1000; + float IDEAL_DUTY_CYCLE = H_PERIOD; + + debug_printf(("12: %f %f\n", H_PERIOD, IDEAL_DUTY_CYCLE)); + + /* 13 */ + float cycle = max(IDEAL_DUTY_CYCLE, 20); + int V_FIELD_RATE = floor(TOTAL_ACTIVE_PIXELS * cycle / (100 - cycle) / 2 / CELL_GRAN_RND) * 2 * CELL_GRAN_RND; + int U40 = V_FIELD_RATE; + + debug_printf(("13: %f %d\n", cycle, V_FIELD_RATE)); + + int H_BLANK = RED_BLANK_RQD ? Y20 : U40; + + /* 14 */ + int V_FRAME_RATE = TOTAL_ACTIVE_PIXELS + H_BLANK; + int U43 = V_FRAME_RATE; + + debug_printf(("14: %d %d\n", V_FRAME_RATE, U43)); + + /* 12' */ + int Y37 = RB_H_BLANK + TOTAL_ACTIVE_PIXELS; + int TOTAL_PIXELS = RED_BLANK_RQD ? Y37 : U43; + + debug_printf(("12': %d %d\n", Y37, TOTAL_PIXELS)); + + /* 15 */ + float PIXEL_FREQ = CLOCK_STEP * floor(TOTAL_PIXELS / H_PERIOD_EST / CLOCK_STEP); + float U46 = PIXEL_FREQ; + /*float U47 = TOTAL_PIXELS / H_PERIOD_EST;*/ + + /* 13' */ + float Y41 = V_FIELD_RATE_RQD * TOTAL_V_LINES * TOTAL_PIXELS / 1000000; + float Y40 = CLOCK_STEP * floor(Y41 / CLOCK_STEP); + float ACT_PIXEL_FREQ = RED_BLANK_RQD ? Y40 : U46; + + /* 16 */ + float U50 = 1000 * ACT_PIXEL_FREQ / TOTAL_PIXELS; + + /* 14' */ + float Y44 = 1000 * ACT_PIXEL_FREQ / TOTAL_PIXELS; + float ACT_H_FREQ = RED_BLANK_RQD ? Y44 : U50; + + /* 17 */ + float U53 = 1000 * ACT_H_FREQ / TOTAL_V_LINES; + + /* 15' */ + float Y47 = 1000 * ACT_H_FREQ / TOTAL_V_LINES; + float ACT_FIELD_RATE = RED_BLANK_RQD ? Y47 : U53; + + /* 18 */ + float U56 = INT_RQD ? ACT_FIELD_RATE / 2 : ACT_FIELD_RATE; + + /* 16' */ + float Y50 = INT_RQD ? ACT_FIELD_RATE / 2 : ACT_FIELD_RATE; + + + /* results */ + float ACT_FRAME_RATE = RED_BLANK_RQD ? Y50 : U56; + float H_BACK_PORCH = H_BLANK / 2; + float H_SYNC_RND = RED_BLANK_RQD ? Y19 : floor(H_SYNC_PER / 100. * TOTAL_PIXELS / CELL_GRAN_RND) * CELL_GRAN_RND; + float H_FRONT_PORCH = H_BLANK - H_BACK_PORCH - H_SYNC_RND; + /*float V_BLANK = RED_BLANK_RQD ? ACT_VBI_LINES : V_SYNC_BP + MIN_V_PORCH_RND;*/ + float V_FRONT_PORCH = RED_BLANK_RQD ? RB_V_FPORCH : MIN_V_PORCH_RND; + /*float V_BACK_PORCH = V_BLANK - V_FRONT_PORCH - Q76;*/ + + debug_printf(("H_BLANK %d\n", H_BLANK)); + debug_printf(("H_BACK_PORCH %f\n", H_BACK_PORCH)); + debug_printf(("H_SYNC_RND %f\n", H_SYNC_RND)); + debug_printf(("H_FRONT_PORCH %f\n", H_FRONT_PORCH)); + + /* finally, pack the results in the mode struct */ + mode m; + + m.hr = (int) (H_PIXELS_RND); + m.hss = (int) (H_PIXELS_RND + H_FRONT_PORCH); + m.hse = (int) (H_PIXELS_RND + H_FRONT_PORCH + H_SYNC_RND); + m.hfl = (int) (TOTAL_PIXELS); + + m.vr = (int) (V_LINES_RND); + m.vss = (int) (V_LINES_RND + V_FRONT_PORCH + INTERLACE); + m.vse = (int) (V_LINES_RND + V_FRONT_PORCH + INTERLACE + V_SYNC_RND); + m.vfl = (int) (TOTAL_V_LINES); + + m.pclk = ACT_PIXEL_FREQ; + m.h_freq = ACT_H_FREQ; + m.v_freq = ACT_FRAME_RATE; + + m.reduced_blanking = RED_BLANK_RQD; + + return (m); + +} + + + + +/* + * parse_command_line() - parse the command line and return an + * alloced structure containing the results. On error print usage + * and return NULL. + */ + +options *parse_command_line (int argc, char *argv[]) +{ + int n; + + options *o = (options *) calloc (1, sizeof (options)); + + if (argc < 4) goto bad_option; + + o->x = atoi (argv[1]); + o->y = atoi (argv[2]); + o->v_freq = atof (argv[3]); + + /* XXX should check for errors in the above */ + + n = 4; + + while (n < argc) { + if ((strcmp (argv[n], "-v") == 0) || + (strcmp (argv[n], "--verbose") == 0)) { + global_verbose = 1; + } else if ((strcmp (argv[n], "--reduced-blanking") == 0)) { + o->reduced_blanking = 1; + } else if ((strcmp (argv[n], "-f") == 0) || + (strcmp (argv[n], "--fbmode") == 0)) { + o->fbmode = 1; + } else if ((strcmp (argv[n], "-x") == 0) || + (strcmp (argv[n], "--xorgmode") == 0) || + (strcmp (argv[n], "--xf86mode") == 0)) { + o->xorgmode = 1; + } else { + goto bad_option; + } + + n++; + } + + /* if neither xorgmode nor fbmode were requested, default to + xorgmode */ + + if (!o->fbmode && !o->xorgmode) o->xorgmode = 1; + + return (o); + + bad_option: + + fprintf (stderr, "\n"); + fprintf (stderr, "usage: %s x y refresh [-v|--verbose] " + "[--reduced-blanking] [-f|--fbmode] [-x|--xorgmode]\n", argv[0]); + + fprintf (stderr, "\n"); + + fprintf (stderr, " x : the desired horizontal " + "resolution (required)\n"); + fprintf (stderr, " y : the desired vertical " + "resolution (required)\n"); + fprintf (stderr, " refresh : the desired refresh " + "rate (required)\n"); + fprintf (stderr, " -v|--verbose : enable verbose printouts " + "(traces each step of the computation)\n"); + fprintf (stderr, " --reduced-blanking : if you want reduced blanking\n"); + fprintf (stderr, " -f|--fbmode : output an fbset(8)-style mode " + "description\n"); + fprintf (stderr, " -x|--xorgmode : output an "__XSERVERNAME__"-style mode " + "description (this is the default\n" + " if no mode description is requested)\n"); + + fprintf (stderr, "\n"); + + free (o); + return (NULL); + +} + + + +int main (int argc, char *argv[]) +{ + mode m; + options *o; + + o = parse_command_line (argc, argv); + if (!o) exit (1); + + m = vert_refresh (o->x, o->y, o->v_freq, o->reduced_blanking, 0, 0); + + if (o->xorgmode) + print_xf86_mode(&m); + + if (o->fbmode) + print_fb_mode(&m); + + return 0; + +} -- cgit v1.2.1