1706f2543Smrg/* 2706f2543Smrg * gtf.c Generate mode timings using the GTF Timing Standard 3706f2543Smrg * 4706f2543Smrg * gcc gtf.c -o gtf -lm -Wall 5706f2543Smrg * 6706f2543Smrg * Copyright (c) 2001, Andy Ritger aritger@nvidia.com 7706f2543Smrg * All rights reserved. 8706f2543Smrg * 9706f2543Smrg * Redistribution and use in source and binary forms, with or without 10706f2543Smrg * modification, are permitted provided that the following conditions 11706f2543Smrg * are met: 12706f2543Smrg * 13706f2543Smrg * o Redistributions of source code must retain the above copyright 14706f2543Smrg * notice, this list of conditions and the following disclaimer. 15706f2543Smrg * o Redistributions in binary form must reproduce the above copyright 16706f2543Smrg * notice, this list of conditions and the following disclaimer 17706f2543Smrg * in the documentation and/or other materials provided with the 18706f2543Smrg * distribution. 19706f2543Smrg * o Neither the name of NVIDIA nor the names of its contributors 20706f2543Smrg * may be used to endorse or promote products derived from this 21706f2543Smrg * software without specific prior written permission. 22706f2543Smrg * 23706f2543Smrg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24706f2543Smrg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 25706f2543Smrg * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 27706f2543Smrg * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28706f2543Smrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29706f2543Smrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30706f2543Smrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31706f2543Smrg * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32706f2543Smrg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33706f2543Smrg * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34706f2543Smrg * POSSIBILITY OF SUCH DAMAGE. 35706f2543Smrg * 36706f2543Smrg * This program is based on the Generalized Timing Formula(GTF TM) 37706f2543Smrg * Standard Version: 1.0, Revision: 1.0 38706f2543Smrg * 39706f2543Smrg * The GTF Document contains the following Copyright information: 40706f2543Smrg * 41706f2543Smrg * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards 42706f2543Smrg * Association. Duplication of this document within VESA member 43706f2543Smrg * companies for review purposes is permitted. All other rights 44706f2543Smrg * reserved. 45706f2543Smrg * 46706f2543Smrg * While every precaution has been taken in the preparation 47706f2543Smrg * of this standard, the Video Electronics Standards Association and 48706f2543Smrg * its contributors assume no responsibility for errors or omissions, 49706f2543Smrg * and make no warranties, expressed or implied, of functionality 50706f2543Smrg * of suitability for any purpose. The sample code contained within 51706f2543Smrg * this standard may be used without restriction. 52706f2543Smrg * 53706f2543Smrg * 54706f2543Smrg * 55706f2543Smrg * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) 56706f2543Smrg * implementation of the GTF Timing Standard, is available at: 57706f2543Smrg * 58706f2543Smrg * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls 59706f2543Smrg */ 60706f2543Smrg 61706f2543Smrg/* Ruthlessly converted to server code by Adam Jackson <ajax@redhat.com> */ 62706f2543Smrg 63706f2543Smrg#ifdef HAVE_XORG_CONFIG_H 64706f2543Smrg# include <xorg-config.h> 65706f2543Smrg#else 66706f2543Smrg#ifdef HAVE_CONFIG_H 67706f2543Smrg#include <config.h> 68706f2543Smrg#endif 69706f2543Smrg#endif 70706f2543Smrg 71706f2543Smrg#include "xf86.h" 72706f2543Smrg#include "xf86Modes.h" 73706f2543Smrg#include <string.h> 74706f2543Smrg 75706f2543Smrg#define MARGIN_PERCENT 1.8 /* % of active vertical image */ 76706f2543Smrg#define CELL_GRAN 8.0 /* assumed character cell granularity */ 77706f2543Smrg#define MIN_PORCH 1 /* minimum front porch */ 78706f2543Smrg#define V_SYNC_RQD 3 /* width of vsync in lines */ 79706f2543Smrg#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ 80706f2543Smrg#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */ 81706f2543Smrg#define M 600.0 /* blanking formula gradient */ 82706f2543Smrg#define C 40.0 /* blanking formula offset */ 83706f2543Smrg#define K 128.0 /* blanking formula scaling factor */ 84706f2543Smrg#define J 20.0 /* blanking formula scaling factor */ 85706f2543Smrg 86706f2543Smrg/* C' and M' are part of the Blanking Duty Cycle computation */ 87706f2543Smrg 88706f2543Smrg#define C_PRIME (((C - J) * K/256.0) + J) 89706f2543Smrg#define M_PRIME (K/256.0 * M) 90706f2543Smrg 91706f2543Smrg 92706f2543Smrg/* 93706f2543Smrg * xf86GTFMode() - as defined by the GTF Timing Standard, compute the 94706f2543Smrg * Stage 1 Parameters using the vertical refresh frequency. In other 95706f2543Smrg * words: input a desired resolution and desired refresh rate, and 96706f2543Smrg * output the GTF mode timings. 97706f2543Smrg * 98706f2543Smrg * XXX All the code is in place to compute interlaced modes, but I don't 99706f2543Smrg * feel like testing it right now. 100706f2543Smrg * 101706f2543Smrg * XXX margin computations are implemented but not tested (nor used by 102706f2543Smrg * XServer of fbset mode descriptions, from what I can tell). 103706f2543Smrg */ 104706f2543Smrg 105706f2543SmrgDisplayModePtr 106706f2543Smrgxf86GTFMode(int h_pixels, int v_lines, float freq, int interlaced, int margins) 107706f2543Smrg{ 108706f2543Smrg DisplayModeRec *mode = xnfcalloc(1, sizeof(DisplayModeRec)); 109706f2543Smrg 110706f2543Smrg float h_pixels_rnd; 111706f2543Smrg float v_lines_rnd; 112706f2543Smrg float v_field_rate_rqd; 113706f2543Smrg float top_margin; 114706f2543Smrg float bottom_margin; 115706f2543Smrg float interlace; 116706f2543Smrg float h_period_est; 117706f2543Smrg float vsync_plus_bp; 118706f2543Smrg float v_back_porch; 119706f2543Smrg float total_v_lines; 120706f2543Smrg float v_field_rate_est; 121706f2543Smrg float h_period; 122706f2543Smrg float v_field_rate; 123706f2543Smrg float v_frame_rate; 124706f2543Smrg float left_margin; 125706f2543Smrg float right_margin; 126706f2543Smrg float total_active_pixels; 127706f2543Smrg float ideal_duty_cycle; 128706f2543Smrg float h_blank; 129706f2543Smrg float total_pixels; 130706f2543Smrg float pixel_freq; 131706f2543Smrg float h_freq; 132706f2543Smrg 133706f2543Smrg float h_sync; 134706f2543Smrg float h_front_porch; 135706f2543Smrg float v_odd_front_porch_lines; 136706f2543Smrg 137706f2543Smrg /* 1. In order to give correct results, the number of horizontal 138706f2543Smrg * pixels requested is first processed to ensure that it is divisible 139706f2543Smrg * by the character size, by rounding it to the nearest character 140706f2543Smrg * cell boundary: 141706f2543Smrg * 142706f2543Smrg * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) 143706f2543Smrg */ 144706f2543Smrg 145706f2543Smrg h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; 146706f2543Smrg 147706f2543Smrg /* 2. If interlace is requested, the number of vertical lines assumed 148706f2543Smrg * by the calculation must be halved, as the computation calculates 149706f2543Smrg * the number of vertical lines per field. In either case, the 150706f2543Smrg * number of lines is rounded to the nearest integer. 151706f2543Smrg * 152706f2543Smrg * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), 153706f2543Smrg * ROUND([V LINES],0)) 154706f2543Smrg */ 155706f2543Smrg 156706f2543Smrg v_lines_rnd = interlaced ? 157706f2543Smrg rint((float) v_lines) / 2.0 : 158706f2543Smrg rint((float) v_lines); 159706f2543Smrg 160706f2543Smrg /* 3. Find the frame rate required: 161706f2543Smrg * 162706f2543Smrg * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, 163706f2543Smrg * [I/P FREQ RQD]) 164706f2543Smrg */ 165706f2543Smrg 166706f2543Smrg v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); 167706f2543Smrg 168706f2543Smrg /* 4. Find number of lines in Top margin: 169706f2543Smrg * 170706f2543Smrg * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 171706f2543Smrg * ROUND(([MARGIN%]/100*[V LINES RND]),0), 172706f2543Smrg * 0) 173706f2543Smrg */ 174706f2543Smrg 175706f2543Smrg top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); 176706f2543Smrg 177706f2543Smrg /* 5. Find number of lines in Bottom margin: 178706f2543Smrg * 179706f2543Smrg * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 180706f2543Smrg * ROUND(([MARGIN%]/100*[V LINES RND]),0), 181706f2543Smrg * 0) 182706f2543Smrg */ 183706f2543Smrg 184706f2543Smrg bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0); 185706f2543Smrg 186706f2543Smrg /* 6. If interlace is required, then set variable [INTERLACE]=0.5: 187706f2543Smrg * 188706f2543Smrg * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) 189706f2543Smrg */ 190706f2543Smrg 191706f2543Smrg interlace = interlaced ? 0.5 : 0.0; 192706f2543Smrg 193706f2543Smrg /* 7. Estimate the Horizontal period 194706f2543Smrg * 195706f2543Smrg * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / 196706f2543Smrg * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + 197706f2543Smrg * [MIN PORCH RND]+[INTERLACE]) * 1000000 198706f2543Smrg */ 199706f2543Smrg 200706f2543Smrg h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0)) 201706f2543Smrg / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace) 202706f2543Smrg * 1000000.0); 203706f2543Smrg 204706f2543Smrg /* 8. Find the number of lines in V sync + back porch: 205706f2543Smrg * 206706f2543Smrg * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) 207706f2543Smrg */ 208706f2543Smrg 209706f2543Smrg vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est); 210706f2543Smrg 211706f2543Smrg /* 9. Find the number of lines in V back porch alone: 212706f2543Smrg * 213706f2543Smrg * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] 214706f2543Smrg * 215706f2543Smrg * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? 216706f2543Smrg */ 217706f2543Smrg 218706f2543Smrg v_back_porch = vsync_plus_bp - V_SYNC_RQD; 219706f2543Smrg 220706f2543Smrg /* 10. Find the total number of lines in Vertical field period: 221706f2543Smrg * 222706f2543Smrg * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + 223706f2543Smrg * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + 224706f2543Smrg * [MIN PORCH RND] 225706f2543Smrg */ 226706f2543Smrg 227706f2543Smrg total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + 228706f2543Smrg interlace + MIN_PORCH; 229706f2543Smrg 230706f2543Smrg /* 11. Estimate the Vertical field frequency: 231706f2543Smrg * 232706f2543Smrg * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 233706f2543Smrg */ 234706f2543Smrg 235706f2543Smrg v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; 236706f2543Smrg 237706f2543Smrg /* 12. Find the actual horizontal period: 238706f2543Smrg * 239706f2543Smrg * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) 240706f2543Smrg */ 241706f2543Smrg 242706f2543Smrg h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); 243706f2543Smrg 244706f2543Smrg /* 13. Find the actual Vertical field frequency: 245706f2543Smrg * 246706f2543Smrg * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 247706f2543Smrg */ 248706f2543Smrg 249706f2543Smrg v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; 250706f2543Smrg 251706f2543Smrg /* 14. Find the Vertical frame frequency: 252706f2543Smrg * 253706f2543Smrg * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) 254706f2543Smrg */ 255706f2543Smrg 256706f2543Smrg v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; 257706f2543Smrg 258706f2543Smrg /* 15. Find number of pixels in left margin: 259706f2543Smrg * 260706f2543Smrg * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 261706f2543Smrg * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 262706f2543Smrg * [CELL GRAN RND]),0)) * [CELL GRAN RND], 263706f2543Smrg * 0)) 264706f2543Smrg */ 265706f2543Smrg 266706f2543Smrg left_margin = margins ? 267706f2543Smrg rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 268706f2543Smrg 0.0; 269706f2543Smrg 270706f2543Smrg /* 16. Find number of pixels in right margin: 271706f2543Smrg * 272706f2543Smrg * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 273706f2543Smrg * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 274706f2543Smrg * [CELL GRAN RND]),0)) * [CELL GRAN RND], 275706f2543Smrg * 0)) 276706f2543Smrg */ 277706f2543Smrg 278706f2543Smrg right_margin = margins ? 279706f2543Smrg rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 280706f2543Smrg 0.0; 281706f2543Smrg 282706f2543Smrg /* 17. Find total number of active pixels in image and left and right 283706f2543Smrg * margins: 284706f2543Smrg * 285706f2543Smrg * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + 286706f2543Smrg * [RIGHT MARGIN (PIXELS)] 287706f2543Smrg */ 288706f2543Smrg 289706f2543Smrg total_active_pixels = h_pixels_rnd + left_margin + right_margin; 290706f2543Smrg 291706f2543Smrg /* 18. Find the ideal blanking duty cycle from the blanking duty cycle 292706f2543Smrg * equation: 293706f2543Smrg * 294706f2543Smrg * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) 295706f2543Smrg */ 296706f2543Smrg 297706f2543Smrg ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); 298706f2543Smrg 299706f2543Smrg /* 19. Find the number of pixels in the blanking time to the nearest 300706f2543Smrg * double character cell: 301706f2543Smrg * 302706f2543Smrg * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * 303706f2543Smrg * [IDEAL DUTY CYCLE] / 304706f2543Smrg * (100-[IDEAL DUTY CYCLE]) / 305706f2543Smrg * (2*[CELL GRAN RND])), 0)) 306706f2543Smrg * * (2*[CELL GRAN RND]) 307706f2543Smrg */ 308706f2543Smrg 309706f2543Smrg h_blank = rint(total_active_pixels * 310706f2543Smrg ideal_duty_cycle / 311706f2543Smrg (100.0 - ideal_duty_cycle) / 312706f2543Smrg (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); 313706f2543Smrg 314706f2543Smrg /* 20. Find total number of pixels: 315706f2543Smrg * 316706f2543Smrg * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] 317706f2543Smrg */ 318706f2543Smrg 319706f2543Smrg total_pixels = total_active_pixels + h_blank; 320706f2543Smrg 321706f2543Smrg /* 21. Find pixel clock frequency: 322706f2543Smrg * 323706f2543Smrg * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] 324706f2543Smrg */ 325706f2543Smrg 326706f2543Smrg pixel_freq = total_pixels / h_period; 327706f2543Smrg 328706f2543Smrg /* 22. Find horizontal frequency: 329706f2543Smrg * 330706f2543Smrg * [H FREQ] = 1000 / [H PERIOD] 331706f2543Smrg */ 332706f2543Smrg 333706f2543Smrg h_freq = 1000.0 / h_period; 334706f2543Smrg 335706f2543Smrg 336706f2543Smrg /* Stage 1 computations are now complete; I should really pass 337706f2543Smrg the results to another function and do the Stage 2 338706f2543Smrg computations, but I only need a few more values so I'll just 339706f2543Smrg append the computations here for now */ 340706f2543Smrg 341706f2543Smrg 342706f2543Smrg /* 17. Find the number of pixels in the horizontal sync period: 343706f2543Smrg * 344706f2543Smrg * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / 345706f2543Smrg * [CELL GRAN RND]),0))*[CELL GRAN RND] 346706f2543Smrg */ 347706f2543Smrg 348706f2543Smrg h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; 349706f2543Smrg 350706f2543Smrg /* 18. Find the number of pixels in the horizontal front porch period: 351706f2543Smrg * 352706f2543Smrg * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] 353706f2543Smrg */ 354706f2543Smrg 355706f2543Smrg h_front_porch = (h_blank / 2.0) - h_sync; 356706f2543Smrg 357706f2543Smrg /* 36. Find the number of lines in the odd front porch period: 358706f2543Smrg * 359706f2543Smrg * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) 360706f2543Smrg */ 361706f2543Smrg 362706f2543Smrg v_odd_front_porch_lines = MIN_PORCH + interlace; 363706f2543Smrg 364706f2543Smrg /* finally, pack the results in the mode struct */ 365706f2543Smrg 366706f2543Smrg mode->HDisplay = (int) (h_pixels_rnd); 367706f2543Smrg mode->HSyncStart = (int) (h_pixels_rnd + h_front_porch); 368706f2543Smrg mode->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync); 369706f2543Smrg mode->HTotal = (int) (total_pixels); 370706f2543Smrg mode->VDisplay = (int) (v_lines_rnd); 371706f2543Smrg mode->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines); 372706f2543Smrg mode->VSyncEnd = (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); 373706f2543Smrg mode->VTotal = (int) (total_v_lines); 374706f2543Smrg 375706f2543Smrg mode->Clock = (int) (pixel_freq * 1000.0); 376706f2543Smrg mode->HSync = h_freq; 377706f2543Smrg mode->VRefresh = freq; 378706f2543Smrg 379706f2543Smrg xf86SetModeDefaultName(mode); 380706f2543Smrg 381706f2543Smrg mode->Flags = V_NHSYNC | V_PVSYNC; 382706f2543Smrg if (interlaced) { 383706f2543Smrg mode->VTotal *= 2; 384706f2543Smrg mode->Flags |= V_INTERLACE; 385706f2543Smrg } 386706f2543Smrg 387706f2543Smrg return mode; 388706f2543Smrg} 389