| 1 | /* |
| 2 | * Copyright 2005-2006 Luc Verhaegen. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice shall be included in |
| 12 | * all copies or substantial portions of the Software. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 20 | * OTHER DEALINGS IN THE SOFTWARE. |
| 21 | */ |
| 22 | |
| 23 | /* |
| 24 | * The reason for having this function in a file of its own is |
| 25 | * so that ../utils/cvt/cvt can link to it, and that xf86CVTMode |
| 26 | * code is shared directly. |
| 27 | */ |
| 28 | |
| 29 | #ifdef HAVE_XORG_CONFIG_H |
| 30 | #include <xorg-config.h> |
| 31 | #else |
| 32 | #ifdef HAVE_CONFIG_H |
| 33 | #include <config.h> |
| 34 | #endif |
| 35 | #endif |
| 36 | |
| 37 | #include "xf86.h" |
| 38 | #include "xf86Modes.h" |
| 39 | |
| 40 | #include <string.h> |
| 41 | |
| 42 | /* |
| 43 | * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. |
| 44 | * |
| 45 | * These calculations are stolen from the CVT calculation spreadsheet written |
| 46 | * by Graham Loveridge. He seems to be claiming no copyright and there seems to |
| 47 | * be no license attached to this. He apparently just wants to see his name |
| 48 | * mentioned. |
| 49 | * |
| 50 | * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls |
| 51 | * |
| 52 | * Comments and structure corresponds to the comments and structure of the xls. |
| 53 | * This should ease importing of future changes to the standard (not very |
| 54 | * likely though). |
| 55 | * |
| 56 | * About margins; i'm sure that they are to be the bit between HDisplay and |
| 57 | * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and |
| 58 | * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking |
| 59 | * outside sync "margin" for some reason. Since we prefer seeing proper |
| 60 | * blanking instead of the overscan colour, and since the Crtc* values will |
| 61 | * probably get altered after us, we will disable margins altogether. With |
| 62 | * these calculations, Margins will plainly expand H/VDisplay, and we don't |
| 63 | * want that. -- libv |
| 64 | * |
| 65 | */ |
| 66 | DisplayModePtr |
| 67 | xf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, |
| 68 | Bool Interlaced) |
| 69 | { |
| 70 | DisplayModeRec *Mode = xnfcalloc(1, sizeof(DisplayModeRec)); |
| 71 | |
| 72 | /* 1) top/bottom margin size (% of height) - default: 1.8 */ |
| 73 | #define CVT_MARGIN_PERCENTAGE 1.8 |
| 74 | |
| 75 | /* 2) character cell horizontal granularity (pixels) - default 8 */ |
| 76 | #define CVT_H_GRANULARITY 8 |
| 77 | |
| 78 | /* 4) Minimum vertical porch (lines) - default 3 */ |
| 79 | #define CVT_MIN_V_PORCH 3 |
| 80 | |
| 81 | /* 4) Minimum number of vertical back porch lines - default 6 */ |
| 82 | #define CVT_MIN_V_BPORCH 6 |
| 83 | |
| 84 | /* Pixel Clock step (kHz) */ |
| 85 | #define CVT_CLOCK_STEP 250 |
| 86 | |
| 87 | Bool Margins = FALSE; |
| 88 | float VFieldRate, HPeriod; |
| 89 | int HDisplayRnd, HMargin; |
| 90 | int VDisplayRnd, VMargin, VSync; |
| 91 | float Interlace; /* Please rename this */ |
| 92 | |
| 93 | /* CVT default is 60.0Hz */ |
| 94 | if (!VRefresh) |
| 95 | VRefresh = 60.0; |
| 96 | |
| 97 | /* 1. Required field rate */ |
| 98 | if (Interlaced) |
| 99 | VFieldRate = VRefresh * 2; |
| 100 | else |
| 101 | VFieldRate = VRefresh; |
| 102 | |
| 103 | /* 2. Horizontal pixels */ |
| 104 | HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY); |
| 105 | |
| 106 | /* 3. Determine left and right borders */ |
| 107 | if (Margins) { |
| 108 | /* right margin is actually exactly the same as left */ |
| 109 | HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); |
| 110 | HMargin -= HMargin % CVT_H_GRANULARITY; |
| 111 | } |
| 112 | else |
| 113 | HMargin = 0; |
| 114 | |
| 115 | /* 4. Find total active pixels */ |
| 116 | Mode->HDisplay = HDisplayRnd + 2 * HMargin; |
| 117 | |
| 118 | /* 5. Find number of lines per field */ |
| 119 | if (Interlaced) |
| 120 | VDisplayRnd = VDisplay / 2; |
| 121 | else |
| 122 | VDisplayRnd = VDisplay; |
| 123 | |
| 124 | /* 6. Find top and bottom margins */ |
| 125 | /* nope. */ |
| 126 | if (Margins) |
| 127 | /* top and bottom margins are equal again. */ |
| 128 | VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); |
| 129 | else |
| 130 | VMargin = 0; |
| 131 | |
| 132 | Mode->VDisplay = VDisplay + 2 * VMargin; |
| 133 | |
| 134 | /* 7. Interlace */ |
| 135 | if (Interlaced) |
| 136 | Interlace = 0.5; |
| 137 | else |
| 138 | Interlace = 0.0; |
| 139 | |
| 140 | /* Determine VSync Width from aspect ratio */ |
| 141 | if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) |
| 142 | VSync = 4; |
| 143 | else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) |
| 144 | VSync = 5; |
| 145 | else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) |
| 146 | VSync = 6; |
| 147 | else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) |
| 148 | VSync = 7; |
| 149 | else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)) |
| 150 | VSync = 7; |
| 151 | else /* Custom */ |
| 152 | VSync = 10; |
| 153 | |
| 154 | if (!Reduced) { /* simplified GTF calculation */ |
| 155 | |
| 156 | /* 4) Minimum time of vertical sync + back porch interval (µs) |
| 157 | * default 550.0 */ |
| 158 | #define CVT_MIN_VSYNC_BP 550.0 |
| 159 | |
| 160 | /* 3) Nominal HSync width (% of line period) - default 8 */ |
| 161 | #define CVT_HSYNC_PERCENTAGE 8 |
| 162 | |
| 163 | float HBlankPercentage; |
| 164 | int VSyncAndBackPorch, VBackPorch; |
| 165 | int HBlank; |
| 166 | |
| 167 | /* 8. Estimated Horizontal period */ |
| 168 | HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / |
| 169 | (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace); |
| 170 | |
| 171 | /* 9. Find number of lines in sync + backporch */ |
| 172 | if (((int) (CVT_MIN_VSYNC_BP / HPeriod) + 1) < |
| 173 | (VSync + CVT_MIN_V_PORCH)) |
| 174 | VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH; |
| 175 | else |
| 176 | VSyncAndBackPorch = (int) (CVT_MIN_VSYNC_BP / HPeriod) + 1; |
| 177 | |
| 178 | /* 10. Find number of lines in back porch */ |
| 179 | VBackPorch = VSyncAndBackPorch - VSync; |
| 180 | |
| 181 | /* 11. Find total number of lines in vertical field */ |
| 182 | Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace |
| 183 | + CVT_MIN_V_PORCH; |
| 184 | |
| 185 | /* 5) Definition of Horizontal blanking time limitation */ |
| 186 | /* Gradient (%/kHz) - default 600 */ |
| 187 | #define CVT_M_FACTOR 600 |
| 188 | |
| 189 | /* Offset (%) - default 40 */ |
| 190 | #define CVT_C_FACTOR 40 |
| 191 | |
| 192 | /* Blanking time scaling factor - default 128 */ |
| 193 | #define CVT_K_FACTOR 128 |
| 194 | |
| 195 | /* Scaling factor weighting - default 20 */ |
| 196 | #define CVT_J_FACTOR 20 |
| 197 | |
| 198 | #define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256 |
| 199 | #define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ |
| 200 | CVT_J_FACTOR |
| 201 | |
| 202 | /* 12. Find ideal blanking duty cycle from formula */ |
| 203 | HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod / 1000.0; |
| 204 | |
| 205 | /* 13. Blanking time */ |
| 206 | if (HBlankPercentage < 20) |
| 207 | HBlankPercentage = 20; |
| 208 | |
| 209 | HBlank = Mode->HDisplay * HBlankPercentage / (100.0 - HBlankPercentage); |
| 210 | HBlank -= HBlank % (2 * CVT_H_GRANULARITY); |
| 211 | |
| 212 | /* 14. Find total number of pixels in a line. */ |
| 213 | Mode->HTotal = Mode->HDisplay + HBlank; |
| 214 | |
| 215 | /* Fill in HSync values */ |
| 216 | Mode->HSyncEnd = Mode->HDisplay + HBlank / 2; |
| 217 | |
| 218 | Mode->HSyncStart = Mode->HSyncEnd - |
| 219 | (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100; |
| 220 | Mode->HSyncStart += CVT_H_GRANULARITY - |
| 221 | Mode->HSyncStart % CVT_H_GRANULARITY; |
| 222 | |
| 223 | /* Fill in VSync values */ |
| 224 | Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH; |
| 225 | Mode->VSyncEnd = Mode->VSyncStart + VSync; |
| 226 | |
| 227 | } |
| 228 | else { /* Reduced blanking */ |
| 229 | /* Minimum vertical blanking interval time (µs) - default 460 */ |
| 230 | #define CVT_RB_MIN_VBLANK 460.0 |
| 231 | |
| 232 | /* Fixed number of clocks for horizontal sync */ |
| 233 | #define CVT_RB_H_SYNC 32.0 |
| 234 | |
| 235 | /* Fixed number of clocks for horizontal blanking */ |
| 236 | #define CVT_RB_H_BLANK 160.0 |
| 237 | |
| 238 | /* Fixed number of lines for vertical front porch - default 3 */ |
| 239 | #define CVT_RB_VFPORCH 3 |
| 240 | |
| 241 | int VBILines; |
| 242 | |
| 243 | /* 8. Estimate Horizontal period. */ |
| 244 | HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / |
| 245 | (VDisplayRnd + 2 * VMargin); |
| 246 | |
| 247 | /* 9. Find number of lines in vertical blanking */ |
| 248 | VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1; |
| 249 | |
| 250 | /* 10. Check if vertical blanking is sufficient */ |
| 251 | if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH)) |
| 252 | VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH; |
| 253 | |
| 254 | /* 11. Find total number of lines in vertical field */ |
| 255 | Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines; |
| 256 | |
| 257 | /* 12. Find total number of pixels in a line */ |
| 258 | Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK; |
| 259 | |
| 260 | /* Fill in HSync values */ |
| 261 | Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2; |
| 262 | Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC; |
| 263 | |
| 264 | /* Fill in VSync values */ |
| 265 | Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH; |
| 266 | Mode->VSyncEnd = Mode->VSyncStart + VSync; |
| 267 | } |
| 268 | |
| 269 | /* 15/13. Find pixel clock frequency (kHz for xf86) */ |
| 270 | Mode->Clock = Mode->HTotal * 1000.0 / HPeriod; |
| 271 | Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP; |
| 272 | |
| 273 | /* 16/14. Find actual Horizontal Frequency (kHz) */ |
| 274 | Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal); |
| 275 | |
| 276 | /* 17/15. Find actual Field rate */ |
| 277 | Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / |
| 278 | ((float) (Mode->HTotal * Mode->VTotal)); |
| 279 | |
| 280 | /* 18/16. Find actual vertical frame frequency */ |
| 281 | /* ignore - just set the mode flag for interlaced */ |
| 282 | if (Interlaced) |
| 283 | Mode->VTotal *= 2; |
| 284 | |
| 285 | XNFasprintf(&Mode->name, "%dx%d", HDisplay, VDisplay); |
| 286 | |
| 287 | if (Reduced) |
| 288 | Mode->Flags |= V_PHSYNC | V_NVSYNC; |
| 289 | else |
| 290 | Mode->Flags |= V_NHSYNC | V_PVSYNC; |
| 291 | |
| 292 | if (Interlaced) |
| 293 | Mode->Flags |= V_INTERLACE; |
| 294 | |
| 295 | return Mode; |
| 296 | } |