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/* 93 * xf86GTFMode() - as defined by the GTF Timing Standard, compute the 94 * Stage 1 Parameters using the vertical refresh frequency. In other 95 * words: input a desired resolution and desired refresh rate, and 96 * output the GTF mode timings. 97 * 98 * XXX All the code is in place to compute interlaced modes, but I don't 99 * feel like testing it right now. 100 * 101 * XXX margin computations are implemented but not tested (nor used by 102 * XServer of fbset mode descriptions, from what I can tell). 103 */ 104 105DisplayModePtr 106xf86GTFMode(int h_pixels, int v_lines, float freq, int interlaced, int margins) 107{ 108 DisplayModeRec *mode = xnfcalloc(1, sizeof(DisplayModeRec)); 109 110 float h_pixels_rnd; 111 float v_lines_rnd; 112 float v_field_rate_rqd; 113 float top_margin; 114 float bottom_margin; 115 float interlace; 116 float h_period_est; 117 float vsync_plus_bp; 118 float v_back_porch; 119 float total_v_lines; 120 float v_field_rate_est; 121 float h_period; 122 float v_field_rate; 123 float v_frame_rate; 124 float left_margin; 125 float right_margin; 126 float total_active_pixels; 127 float ideal_duty_cycle; 128 float h_blank; 129 float total_pixels; 130 float pixel_freq; 131 float h_freq; 132 133 float h_sync; 134 float h_front_porch; 135 float v_odd_front_porch_lines; 136 137 /* 1. In order to give correct results, the number of horizontal 138 * pixels requested is first processed to ensure that it is divisible 139 * by the character size, by rounding it to the nearest character 140 * cell boundary: 141 * 142 * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) 143 */ 144 145 h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN; 146 147 /* 2. If interlace is requested, the number of vertical lines assumed 148 * by the calculation must be halved, as the computation calculates 149 * the number of vertical lines per field. In either case, the 150 * number of lines is rounded to the nearest integer. 151 * 152 * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), 153 * ROUND([V LINES],0)) 154 */ 155 156 v_lines_rnd = interlaced ? 157 rint((float) v_lines) / 2.0 : 158 rint((float) v_lines); 159 160 /* 3. Find the frame rate required: 161 * 162 * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, 163 * [I/P FREQ RQD]) 164 */ 165 166 v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq); 167 168 /* 4. Find number of lines in Top margin: 169 * 170 * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 171 * ROUND(([MARGIN%]/100*[V LINES RND]),0), 172 * 0) 173 */ 174 175 top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); 176 177 /* 5. Find number of lines in Bottom margin: 178 * 179 * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 180 * ROUND(([MARGIN%]/100*[V LINES RND]),0), 181 * 0) 182 */ 183 184 bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0); 185 186 /* 6. If interlace is required, then set variable [INTERLACE]=0.5: 187 * 188 * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) 189 */ 190 191 interlace = interlaced ? 0.5 : 0.0; 192 193 /* 7. Estimate the Horizontal period 194 * 195 * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) / 196 * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) + 197 * [MIN PORCH RND]+[INTERLACE]) * 1000000 198 */ 199 200 h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0)) 201 / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace) 202 * 1000000.0); 203 204 /* 8. Find the number of lines in V sync + back porch: 205 * 206 * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) 207 */ 208 209 vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est); 210 211 /* 9. Find the number of lines in V back porch alone: 212 * 213 * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND] 214 * 215 * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]? 216 */ 217 218 v_back_porch = vsync_plus_bp - V_SYNC_RQD; 219 220 /* 10. Find the total number of lines in Vertical field period: 221 * 222 * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] + 223 * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + 224 * [MIN PORCH RND] 225 */ 226 227 total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + 228 interlace + MIN_PORCH; 229 230 /* 11. Estimate the Vertical field frequency: 231 * 232 * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 233 */ 234 235 v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0; 236 237 /* 12. Find the actual horizontal period: 238 * 239 * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) 240 */ 241 242 h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est); 243 244 /* 13. Find the actual Vertical field frequency: 245 * 246 * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000 247 */ 248 249 v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0; 250 251 /* 14. Find the Vertical frame frequency: 252 * 253 * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE])) 254 */ 255 256 v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate; 257 258 /* 15. Find number of pixels in left margin: 259 * 260 * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 261 * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 262 * [CELL GRAN RND]),0)) * [CELL GRAN RND], 263 * 0)) 264 */ 265 266 left_margin = margins ? 267 rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 268 0.0; 269 270 /* 16. Find number of pixels in right margin: 271 * 272 * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 273 * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 274 * [CELL GRAN RND]),0)) * [CELL GRAN RND], 275 * 0)) 276 */ 277 278 right_margin = margins ? 279 rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 280 0.0; 281 282 /* 17. Find total number of active pixels in image and left and right 283 * margins: 284 * 285 * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + 286 * [RIGHT MARGIN (PIXELS)] 287 */ 288 289 total_active_pixels = h_pixels_rnd + left_margin + right_margin; 290 291 /* 18. Find the ideal blanking duty cycle from the blanking duty cycle 292 * equation: 293 * 294 * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) 295 */ 296 297 ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0); 298 299 /* 19. Find the number of pixels in the blanking time to the nearest 300 * double character cell: 301 * 302 * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] * 303 * [IDEAL DUTY CYCLE] / 304 * (100-[IDEAL DUTY CYCLE]) / 305 * (2*[CELL GRAN RND])), 0)) 306 * * (2*[CELL GRAN RND]) 307 */ 308 309 h_blank = rint(total_active_pixels * 310 ideal_duty_cycle / 311 (100.0 - ideal_duty_cycle) / 312 (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN); 313 314 /* 20. Find total number of pixels: 315 * 316 * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] 317 */ 318 319 total_pixels = total_active_pixels + h_blank; 320 321 /* 21. Find pixel clock frequency: 322 * 323 * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] 324 */ 325 326 pixel_freq = total_pixels / h_period; 327 328 /* 22. Find horizontal frequency: 329 * 330 * [H FREQ] = 1000 / [H PERIOD] 331 */ 332 333 h_freq = 1000.0 / h_period; 334 335 336 /* Stage 1 computations are now complete; I should really pass 337 the results to another function and do the Stage 2 338 computations, but I only need a few more values so I'll just 339 append the computations here for now */ 340 341 342 /* 17. Find the number of pixels in the horizontal sync period: 343 * 344 * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] / 345 * [CELL GRAN RND]),0))*[CELL GRAN RND] 346 */ 347 348 h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN; 349 350 /* 18. Find the number of pixels in the horizontal front porch period: 351 * 352 * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] 353 */ 354 355 h_front_porch = (h_blank / 2.0) - h_sync; 356 357 /* 36. Find the number of lines in the odd front porch period: 358 * 359 * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) 360 */ 361 362 v_odd_front_porch_lines = MIN_PORCH + interlace; 363 364 /* finally, pack the results in the mode struct */ 365 366 mode->HDisplay = (int) (h_pixels_rnd); 367 mode->HSyncStart = (int) (h_pixels_rnd + h_front_porch); 368 mode->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync); 369 mode->HTotal = (int) (total_pixels); 370 mode->VDisplay = (int) (v_lines_rnd); 371 mode->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines); 372 mode->VSyncEnd = (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD); 373 mode->VTotal = (int) (total_v_lines); 374 375 mode->Clock = (int) (pixel_freq * 1000.0); 376 mode->HSync = h_freq; 377 mode->VRefresh = freq; 378 379 xf86SetModeDefaultName(mode); 380 381 mode->Flags = V_NHSYNC | V_PVSYNC; 382 if (interlaced) { 383 mode->VTotal *= 2; 384 mode->Flags |= V_INTERLACE; 385 } 386 387 return mode; 388} 389