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