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