Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |