1 /* 2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /* Generate mode timings using the GTF Timing Standard 7 * 8 * Copyright (c) 2001, Andy Ritger aritger@nvidia.com 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * o Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * o Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer 19 * in the documentation and/or other materials provided with the 20 * distribution. 21 * o Neither the name of NVIDIA nor the names of its contributors 22 * may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 * 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 28 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 29 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 30 * THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 * 39 * 40 * 41 * This program is based on the Generalized Timing Formula(GTF TM) 42 * Standard Version: 1.0, Revision: 1.0 43 * 44 * The GTF Document contains the following Copyright information: 45 * 46 * Copyright (c) 1994, 1995, 1996 - Video Electronics Standards 47 * Association. Duplication of this document within VESA member 48 * companies for review purposes is permitted. All other rights 49 * reserved. 50 * 51 * While every precaution has been taken in the preparation 52 * of this standard, the Video Electronics Standards Association and 53 * its contributors assume no responsibility for errors or omissions, 54 * and make no warranties, expressed or implied, of functionality 55 * of suitability for any purpose. The sample code contained within 56 * this standard may be used without restriction. 57 * 58 * 59 * 60 * The GTF EXCEL(TM) SPREADSHEET, a sample (and the definitive) 61 * implementation of the GTF Timing Standard, is available at: 62 * 63 * ftp://ftp.vesa.org/pub/GTF/GTF_V1R1.xls 64 * 65 * 66 * 67 * This program takes a desired resolution and vertical refresh rate, 68 * and computes mode timings according to the GTF Timing Standard. 69 * These mode timings can then be formatted as an XFree86 modeline 70 * or a mode description for use by fbset(8). 71 * 72 * NOTES: 73 * 74 * The GTF allows for computation of "margins" (the visible border 75 * surrounding the addressable video); on most non-overscan type 76 * systems, the margin period is zero. I've implemented the margin 77 * computations but not enabled it because 1) I don't really have 78 * any experience with this, and 2) neither XFree86 modelines nor 79 * fbset fb.modes provide an obvious way for margin timings to be 80 * included in their mode descriptions (needs more investigation). 81 * 82 * The GTF provides for computation of interlaced mode timings; 83 * I've implemented the computations but not enabled them, yet. 84 * I should probably enable and test this at some point. 85 * 86 * TODO: 87 * 88 * o Add support for interlaced modes. 89 * 90 * o Implement the other portions of the GTF: compute mode timings 91 * given either the desired pixel clock or the desired horizontal 92 * frequency. 93 * 94 * o It would be nice if this were more general purpose to do things 95 * outside the scope of the GTF: like generate double scan mode 96 * timings, for example. 97 * 98 * o Error checking. 99 * 100 */ 101 102 103 #include <compute_display_timing.h> 104 105 #include <math.h> 106 #include <stdarg.h> 107 108 109 //#define TRACE_COMPUTE 110 #ifdef TRACE_COMPUTE 111 # define TRACE(x, ...) debug_printf(x, __VA_ARGS__) 112 #else 113 # define TRACE(x, ...) ; 114 #endif 115 116 117 #define MARGIN_PERCENT 1.8 // % of active vertical image 118 #define CELL_GRANULARITY 8.0 119 // assumed character cell granularity 120 #define MIN_PORCH 1 // minimum front porch 121 #define V_SYNC_WIDTH 3 // width of vsync in lines 122 #define H_SYNC_PERCENT 8.0 // width of hsync as % of total line 123 #define MIN_VSYNC_PLUS_BACK_PORCH 550.0 // time in microsec 124 125 // C' and M' are part of the Blanking Duty Cycle computation 126 127 #define M 600.0 // blanking formula gradient 128 #define C 40.0 // blanking formula offset 129 #define K 128.0 // blanking formula scaling factor 130 #define J 20.0 // blanking formula scaling factor 131 #define C_PRIME (((C - J) * K / 256.0) + J) 132 #define M_PRIME (K / 256.0 * M) 133 134 135 /*! As defined by the GTF Timing Standard, compute the Stage 1 Parameters 136 using the vertical refresh frequency. In other words: input a desired 137 resolution and desired refresh rate, and output the GTF mode timings. 138 */ 139 status_t 140 compute_display_timing(uint32 width, uint32 height, float refresh, 141 bool interlaced, display_timing* timing) 142 { 143 if (width < 320 || height < 200 || width > 65536 || height > 65536 144 || refresh < 25 || refresh > 1000) 145 return B_BAD_VALUE; 146 147 bool margins = false; 148 149 // 1. In order to give correct results, the number of horizontal 150 // pixels requested is first processed to ensure that it is divisible 151 // by the character size, by rounding it to the nearest character 152 // cell boundary: 153 // [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND]) 154 width = (uint32)(rint(width / CELL_GRANULARITY) * CELL_GRANULARITY); 155 156 // 2. If interlace is requested, the number of vertical lines assumed 157 // by the calculation must be halved, as the computation calculates 158 // the number of vertical lines per field. In either case, the 159 // number of lines is rounded to the nearest integer. 160 // [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0), 161 // ROUND([V LINES],0)) 162 float verticalLines = interlaced ? (double)height / 2.0 : (double)height; 163 164 // 3. Find the frame rate required: 165 // [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2, 166 // [I/P FREQ RQD]) 167 float verticalFieldRate = interlaced ? refresh * 2.0 : refresh; 168 169 // 4. Find number of lines in Top margin: 170 // [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 171 // ROUND(([MARGIN%]/100*[V LINES RND]),0), 0) 172 float topMargin = margins ? rint(MARGIN_PERCENT / 100.0 * verticalLines) 173 : 0.0; 174 175 // 5. Find number of lines in Bottom margin: 176 // [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", 177 // ROUND(([MARGIN%]/100*[V LINES RND]),0), 0) 178 float bottomMargin = margins ? rint(MARGIN_PERCENT / 100.0 * verticalLines) 179 : 0.0; 180 181 // 6. If interlace is required, then set variable [INTERLACE]=0.5: 182 // [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) 183 float interlace = interlaced ? 0.5 : 0.0; 184 185 // 7. Estimate the Horizontal period 186 // [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) 187 // / ([V LINES RND] + (2*[TOP MARGIN (LINES)]) 188 // + [MIN PORCH RND]+[INTERLACE]) * 1000000 189 float horizontalPeriodEstimate = (1.0 / verticalFieldRate 190 - MIN_VSYNC_PLUS_BACK_PORCH / 1000000.0) 191 / (verticalLines + (2 * topMargin) + MIN_PORCH + interlace) * 1000000.0; 192 193 // 8. Find the number of lines in V sync + back porch: 194 // [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0) 195 float verticalSyncPlusBackPorch = rint(MIN_VSYNC_PLUS_BACK_PORCH 196 / horizontalPeriodEstimate); 197 198 // 10. Find the total number of lines in Vertical field period: 199 // [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] 200 // + [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] + [MIN PORCH RND] 201 float totalVerticalLines = verticalLines + topMargin + bottomMargin 202 + verticalSyncPlusBackPorch + interlace + MIN_PORCH; 203 204 // 11. Estimate the Vertical field frequency: 205 // [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000 206 float verticalFieldRateEstimate = 1.0 / horizontalPeriodEstimate 207 / totalVerticalLines * 1000000.0; 208 209 // 12. Find the actual horizontal period: 210 // [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST]) 211 float horizontalPeriod = horizontalPeriodEstimate 212 / (verticalFieldRate / verticalFieldRateEstimate); 213 214 // 15. Find number of pixels in left margin: 215 // [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 216 // (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 217 // [CELL GRAN RND]),0)) * [CELL GRAN RND], 0)) 218 float leftMargin = margins ? rint(width * MARGIN_PERCENT / 100.0 219 / CELL_GRANULARITY) * CELL_GRANULARITY : 0.0; 220 221 // 16. Find number of pixels in right margin: 222 // [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", 223 // (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 / 224 // [CELL GRAN RND]),0)) * [CELL GRAN RND], 0)) 225 float rightMargin = margins ? rint(width * MARGIN_PERCENT / 100.0 226 / CELL_GRANULARITY) * CELL_GRANULARITY : 0.0; 227 228 // 17. Find total number of active pixels in image and left and right 229 // margins: 230 // [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] 231 // + [RIGHT MARGIN (PIXELS)] 232 float totalActivePixels = width + leftMargin + rightMargin; 233 234 // 18. Find the ideal blanking duty cycle from the blanking duty cycle 235 // equation: 236 // [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000) 237 float idealDutyCycle = C_PRIME - (M_PRIME * horizontalPeriod / 1000.0); 238 239 // 19. Find the number of pixels in the blanking time to the nearest 240 // double character cell: 241 // [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] 242 // * [IDEAL DUTY CYCLE] / (100-[IDEAL DUTY CYCLE]) 243 // / (2*[CELL GRAN RND])), 0)) * (2*[CELL GRAN RND]) 244 float horizontalBlank = rint(totalActivePixels * idealDutyCycle 245 / (100.0 - idealDutyCycle) / (2.0 * CELL_GRANULARITY)) 246 * (2.0 * CELL_GRANULARITY); 247 248 // 20. Find total number of pixels: 249 // [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)] 250 float totalPixels = totalActivePixels + horizontalBlank; 251 252 // 21. Find pixel clock frequency: 253 // [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD] 254 float pixelFrequency = totalPixels / horizontalPeriod; 255 256 // Stage 1 computations are now complete; I should really pass 257 // the results to another function and do the Stage 2 258 // computations, but I only need a few more values so I'll just 259 // append the computations here for now */ 260 261 // 17. Find the number of pixels in the horizontal sync period: 262 // [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] 263 // / [CELL GRAN RND]),0))*[CELL GRAN RND] 264 float horizontalSync = rint(H_SYNC_PERCENT / 100.0 * totalPixels 265 / CELL_GRANULARITY) * CELL_GRANULARITY; 266 267 // 18. Find the number of pixels in the horizontal front porch period: 268 // [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)] 269 float horizontalFrontPorch = (horizontalBlank / 2.0) - horizontalSync; 270 271 // 36. Find the number of lines in the odd front porch period: 272 // [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE]) 273 float verticalOddFrontPorchLines = MIN_PORCH + interlace; 274 275 // finally, pack the results in the mode struct 276 277 timing->pixel_clock = uint32(pixelFrequency * 1000); 278 timing->h_display = (uint16)width; 279 timing->h_sync_start = (uint16)(width + horizontalFrontPorch); 280 timing->h_sync_end 281 = (uint16)(width + horizontalFrontPorch + horizontalSync); 282 timing->h_total = (uint16)totalPixels; 283 timing->v_display = (uint16)verticalLines; 284 timing->v_sync_start = (uint16)(verticalLines + verticalOddFrontPorchLines); 285 timing->v_sync_end 286 = (uint16)(verticalLines + verticalOddFrontPorchLines + V_SYNC_WIDTH); 287 timing->v_total = (uint16)totalVerticalLines; 288 timing->flags = B_POSITIVE_HSYNC | B_POSITIVE_VSYNC 289 | (interlace ? B_TIMING_INTERLACED : 0); 290 291 TRACE("GTF TIMING: %lu kHz, (%u, %u, %u, %u), (%u, %u, %u, %u)\n", 292 timing->pixel_clock, timing->h_display, timing->h_sync_start, 293 timing->h_sync_end, timing->h_total, timing->v_display, 294 timing->v_sync_start, timing->v_sync_end, timing->v_total); 295 296 return B_OK; 297 } 298