| 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 | } |